/** @file  wifidirectutl.c
 *
 *  @brief Program to configure WifiDirect parameters.
 *
 *   Usage: ./wifidirectutl <iface> <command> <params> 
 * 
 * (C) Copyright 2008-2011 Marvell International Ltd. All Rights Reserved
 *
 * MARVELL CONFIDENTIAL
 * The source code contained or described herein and all documents related to
 * the source code ("Material") are owned by Marvell International Ltd or its
 * suppliers or licensors. Title to the Material remains with Marvell International Ltd
 * or its suppliers and licensors. The Material contains trade secrets and
 * proprietary and confidential information of Marvell or its suppliers and
 * licensors. The Material is protected by worldwide copyright and trade secret
 * laws and treaty provisions. No part of the Material may be used, copied,
 * reproduced, modified, published, uploaded, posted, transmitted, distributed,
 * or disclosed in any way without Marvell's prior express written permission.
 *
 * No license under any patent, copyright, trade secret or other intellectual
 * property right is granted to or conferred upon you by disclosure or delivery
 * of the Materials, either expressly, by implication, inducement, estoppel or
 * otherwise. Any license under such intellectual property rights must be
 * express and approved by Marvell in writing.
 *
 */
/****************************************************************************
  Change log:
  07/10/09: Initial creation
 ****************************************************************************/

/****************************************************************************
  Header files
 ****************************************************************************/
#include <stdarg.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <stdio.h>
#include <getopt.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <linux/if.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <linux/wireless.h>
#include "wifidirectutl.h"
#include "wifi_display.h"
/****************************************************************************
  Definitions
 ****************************************************************************/

/** Convert character to integer */
#define CHAR2INT(x) (((x) >= 'A') ? ((x) - 'A' + 10) : ((x) - '0'))

/** Uncomment this to enable DEBUG */
/* #define DEBUG */

/****************************************************************************
  Global variables
 ****************************************************************************/
/** Device name */
char dev_name[IFNAMSIZ + 1];
/** Option for cmd */
struct option cmd_options[] = {
    {"help", 0, 0, 'h'},
    {0, 0, 0, 0}
};

/****************************************************************************
  Local functions
 ***************************************************************************/
/**
 *  @brief Dump hex data
 *
 *  @param p        A pointer to data buffer
 *  @param len      The len of data buffer
 *  @param delim    Deliminator character
 *  @return         Hex integer
 */
#ifdef DEBUG
static void
hexdump(void *p, t_s32 len, t_s8 delim)
{
    t_s32 i;
    t_u8 *s = p;
    printf("HexDump: len=%d\n", (int) len);
    for (i = 0; i < len; i++) {
        if (i != len - 1)
            printf("%02x%c", *s++, delim);
        else
            printf("%02x\n", *s);
        if ((i + 1) % 16 == 0)
            printf("\n");
    }
}
#endif

static int
wifidir_use_fixed_ie_indices(void)
{
#define WIFIDIR_USE_FIXED_IE_INDICES "WIFIDIR_USE_FIXED_IE_INDICES"
    char *ret = getenv(WIFIDIR_USE_FIXED_IE_INDICES);

    if (ret != NULL && *ret == '1') {
        printf("Using fixed ie indices 0 and 1 for P2P and WPS IEs");
        return 1;
    } else {
        return 0;
    }
}

/**
 *    @brief isdigit for String.
 *   
 *    @param x            Char string
 *    @return             FAILURE for non-digit.
 *                        SUCCESS for digit
 */
inline int
ISDIGIT(char *x)
{
    unsigned int i;
    for (i = 0; i < strlen(x); i++)
        if (isdigit(x[i]) == 0)
            return FAILURE;
    return SUCCESS;
}

/** 
 *  @brief Converts a string to hex value
 *
 *  @param str      A pointer to the string
 *  @param raw      A pointer to the raw data buffer
 *  @return         Number of bytes read
 */
static int
string2raw(char *str, unsigned char *raw)
{
    int len = (strlen(str) + 1) / 2;

    do {
        if (!isxdigit(*str)) {
            return -1;
        }
        *str = toupper(*str);
        *raw = CHAR2INT(*str) << 4;
        ++str;
        *str = toupper(*str);
        if (*str == '\0')
            break;
        *raw |= CHAR2INT(*str);
        ++raw;
    } while (*++str != '\0');
    return len;
}

/** 
 *    @brief Convert string to hex integer
 *  
 *    @param s            A pointer string buffer
 *    @return             Hex integer
 */
unsigned int
a2hex(char *s)
{
    unsigned int val = 0;
    if (!strncasecmp("0x", s, 2)) {
        s += 2;
    }
    while (*s && isxdigit(*s)) {
        val = (val << 4) + hexc2bin(*s++);
    }
    return val;
}

/** 
 *  @brief      Hex to number 
 *
 *  @param c    Hex value
 *  @return     Integer value or -1
 */
static int
hex2num(char c)
{
    if (c >= '0' && c <= '9')
        return c - '0';
    if (c >= 'a' && c <= 'f')
        return c - 'a' + 10;
    if (c >= 'A' && c <= 'F')
        return c - 'A' + 10;

    return -1;
}

/**
 *    @brief Convert char to hex integer
 *   
 *    @param chr          Char
 *    @return             Hex integer
 */
unsigned char
hexc2bin(char chr)
{
    if (chr >= '0' && chr <= '9')
        chr -= '0';
    else if (chr >= 'A' && chr <= 'F')
        chr -= ('A' - 10);
    else if (chr >= 'a' && chr <= 'f')
        chr -= ('a' - 10);

    return chr;
}

/** 
 *  @brief              Check hex string
 *  
 *  @param hex          A pointer to hex string
 *  @return             SUCCESS or FAILURE
 */
static int
ishexstring(void *hex)
{
    int i, a;
    char *p = hex;
    int len = strlen(p);
    if (!strncasecmp("0x", p, 2)) {
        p += 2;
        len -= 2;
    }
    for (i = 0; i < len; i++) {
        a = hex2num(*p);
        if (a < 0)
            return FAILURE;
        p++;
    }
    return SUCCESS;
}

/** 
 *  @brief Prints a MAC address in colon separated form from hex data
 *
 *  @param raw      A pointer to the hex data buffer
 *  @return         N/A
 */
static void
print_mac(t_u8 * raw)
{
    printf("%02x:%02x:%02x:%02x:%02x:%02x", (unsigned int) raw[0],
           (unsigned int) raw[1], (unsigned int) raw[2], (unsigned int) raw[3],
           (unsigned int) raw[4], (unsigned int) raw[5]);
    return;
}

/** 
 *  @brief Converts colon separated MAC address to hex value
 *
 *  @param mac      A pointer to the colon separated MAC string
 *  @param raw      A pointer to the hex data buffer
 *  @return         SUCCESS or FAILURE
 *                  WIFIDIRECT_RET_MAC_BROADCAST  - if broadcast mac
 *                  WIFIDIRECT_RET_MAC_MULTICAST - if multicast mac
 */
int
mac2raw(char *mac, t_u8 * raw)
{
    unsigned int temp_raw[ETH_ALEN];
    int num_tokens = 0;
    int i;
    if (strlen(mac) != ((2 * ETH_ALEN) + (ETH_ALEN - 1))) {
        return FAILURE;
    }
    num_tokens = sscanf(mac, "%2x:%2x:%2x:%2x:%2x:%2x",
                        temp_raw + 0, temp_raw + 1, temp_raw + 2, temp_raw + 3,
                        temp_raw + 4, temp_raw + 5);
    if (num_tokens != ETH_ALEN) {
        return FAILURE;
    }
    for (i = 0; i < num_tokens; i++)
        raw[i] = (t_u8) temp_raw[i];

    if (memcmp(raw, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0) {
        return WIFIDIRECT_RET_MAC_BROADCAST;
    } else if (raw[0] & 0x01) {
        return WIFIDIRECT_RET_MAC_MULTICAST;
    }
    return SUCCESS;
}

/** 
 *  @brief Prints usage information of wifidirectutl
 *
 *  @return          N/A
 */
static void
print_tool_usage(void)
{

    printf("Usage:\n");
    printf("./wifidirectutl <iface> wifidirect_mode [mode]\n"
           "./wifidirectutl <iface> wifidirect_config [*.conf]\n"
           "./wifidirectutl <iface> wifidirect_params_config [*.conf]\n"
           "./wifidirectutl <iface> wifidirect_action_frame <*.conf>|"
           "	<PeerAddr> <Category> <OuiSubtype> <DialogToken>\n"
           "./wifidirectutl <iface> wifidirect_discovery_request <*.conf>\n"
           "./wifidirectutl <iface> wifidirect_discovery_response <*.conf>\n"
           "./wifidirectutl <iface> wifidirect_gas_comeback_request <*.conf>\n"
           "./wifidirectutl <iface> wifidirect_gas_comeback_response <*.conf>\n"
           "./wifidirectutl <iface> wifidisplay_config [*.conf]\n"
           "./wifidirectutl <iface> wifidisplay_mode [enable/disable]\n"
           "./wifidirectutl <iface> wifidisplay_update_devinfo [value]\n"
           "./wifidirectutl <iface> wifidisplay_update_coupledsink_bitmap [value <= 255]\n"
           "./wifidirectutl <iface> wifidisplay_discovery_request [*.config]\n"
           "./wifidirectutl <iface> wifidisplay_discovery_response [*.config]\n");
    printf
        ("\nPlease see example configuration file config/wifidirect.conf\n\n");
    printf("Configuration API:\n");
    printf
        ("./wifidirectutl <iface> wifidirect_cfg_discovery_period [<MinDiscPeriod> <MaxDiscPeriod>]\n"
         "./wifidirectutl <iface> wifidirect_cfg_intent [IntentValue]\n"
         "./wifidirectutl <iface> wifidirect_cfg_capability [<deviceCapability> <groupCapability>]\n"
         "./wifidirectutl <iface> wifidirect_cfg_noa <enable | disable> [<counttype> <duration> <interval>]\n"
         "./wifidirectutl <iface> wifidirect_cfg_opp_ps [<enable> <CTWindow>]\n"
         "./wifidirectutl <iface> wifidirect_cfg_invitation_list [mac_address]\n"
         "./wifidirectutl <iface> wifidirect_cfg_listen_channel [listenChannel]\n"
         "./wifidirectutl <iface> wifidirect_cfg_op_channel [operatingChannel]\n"
         "./wifidirecttul <iface> wifidirect_cfg_persistent_group_record [index] [role]\n"
         "	[<groupbss> <deviceId> <ssid> <psk>] [peermac1] [peermac2]\n"
         "./wifidirecttul <iface> wifidirect_cfg_persistent_group_invoke [index] | <cancel>\n"
         "./wifidirectutl <iface> wifidirect_cfg_presence_req_params [<type> <duration> <interval>]\n"
         "./wifidirectutl <iface> wifidirect_cfg_ext_listen_time [<duration> <interval>]\n");

}

/** 
 *  @brief Parses a command line
 *
 *  @param line     The line to parse
 *  @param args     Pointer to the argument buffer to be filled in
 *  @return         Number of arguments in the line or EOF
 */
int
parse_line(char *line, char *args[])
{
    int arg_num = 0;
    int is_start = 0;
    int is_quote = 0;
    int length = 0;
    int i = 0;

    arg_num = 0;
    length = strlen(line);
    /* Process line */

    /* Find number of arguments */
    is_start = 0;
    is_quote = 0;
    for (i = 0; i < length; i++) {
        /* Ignore leading spaces */
        if (is_start == 0) {
            if (line[i] == ' ') {
                continue;
            } else if (line[i] == '\t') {
                continue;
            } else if (line[i] == '\n') {
                break;
            } else {
                is_start = 1;
                args[arg_num] = &line[i];
                arg_num++;
            }
        }
        if (is_start == 1) {
            /* Ignore comments */
            if (line[i] == '#') {
                if (is_quote == 0) {
                    line[i] = '\0';
                    arg_num--;
                }
                break;
            }
            /* Separate by '=' */
            if (line[i] == '=') {
                line[i] = '\0';
                is_start = 0;
                continue;
            }
            /* Separate by ',' */
            if (line[i] == ',') {
                line[i] = '\0';
                is_start = 0;
                continue;
            }
            /* Change ',' to ' ', but not inside quotes */
            if ((line[i] == ',') && (is_quote == 0)) {
                line[i] = ' ';
                continue;
            }
        }
        /* Remove newlines */
        if (line[i] == '\n') {
            line[i] = '\0';
        }
        /* Check for quotes */
        if (line[i] == '"') {
            is_quote = (is_quote == 1) ? 0 : 1;
            continue;
        }
        if (((line[i] == ' ') || (line[i] == '\t')) && (is_quote == 0)) {
            line[i] = '\0';
            is_start = 0;
            continue;
        }
    }
    return arg_num;
}

/** 
 *  @brief      Parse function for a configuration line  
 *
 *  @param s        Storage buffer for data
 *  @param size     Maximum size of data
 *  @param stream   File stream pointer
 *  @param line     Pointer to current line within the file
 *  @param _pos     Output string or NULL
 *  @return     String or NULL
 */
char *
config_get_line(char *s, int size, FILE * stream, int *line, char **_pos)
{
    char *pos, *end, *sstart;
    while (fgets(s, size, stream)) {
        (*line)++;
        s[size - 1] = '\0';
        pos = s;
        /* Skip white space from the beginning of line. */
        while (*pos == ' ' || *pos == '\t' || *pos == '\r')
            pos++;
        /* Skip comment lines and empty lines */
        if (*pos == '#' || *pos == '\n' || *pos == '\0')
            continue;
        /* 
         * Remove # comments unless they are within a double quoted
         * string.
         */
        sstart = strchr(pos, '"');
        if (sstart)
            sstart = strrchr(sstart + 1, '"');
        if (!sstart)
            sstart = pos;
        end = strchr(sstart, '#');
        if (end)
            *end-- = '\0';
        else
            end = pos + strlen(pos) - 1;
        /* Remove trailing white space. */
        while (end > pos &&
               (*end == '\n' || *end == ' ' || *end == '\t' || *end == '\r'))
            *end-- = '\0';
        if (*pos == '\0')
            continue;
        if (_pos)
            *_pos = pos;
        return pos;
    }

    if (_pos)
        *_pos = NULL;
    return NULL;
}

/**
 *  @brief  Detects duplicates channel in array of strings
 *          
 *  @param  argc    Number of elements
 *  @param  argv    Array of strings
 *  @return UAP_FAILURE or UAP_SUCCESS
 */
static inline int
has_dup_channel(int argc, char *argv[])
{
    int i, j;
    /* Check for duplicate */
    for (i = 0; i < (argc - 1); i++) {
        for (j = i + 1; j < argc; j++) {
            if (atoi(argv[i]) == atoi(argv[j])) {
                return FAILURE;
            }
        }
    }
    return SUCCESS;
}

/** 
 *  @brief Performs the ioctl operation to send the command to
 *  the driver.
 *
 *  @param cmd           Pointer to the command buffer
 *  @param size          Pointer to the command size. This value is
 *                       overwritten by the function with the size of the
 *                       received response.
 *  @param buf_size      Size of the allocated command buffer
 *  @return              SUCCESS or FAILURE
 */
int
wifidirect_ioctl(t_u8 * cmd, t_u16 * size, t_u16 buf_size)
{
    struct ifreq ifr;
    mrvl_priv_cmd *mrvl_cmd = NULL;
    t_u8 *buf = NULL, *temp = NULL;
    wifidirectcmdbuf *header = NULL;
    t_s32 sockfd;
    t_u16 mrvl_header_len = 0;
    int ret = SUCCESS;

    if (buf_size < *size) {
        printf("buf_size should not less than cmd buffer size\n");
        return FAILURE;
    }

    /* Open socket */
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("ERR:Cannot open socket\n");
        return FAILURE;
    }
    *(t_u32 *) cmd = buf_size - BUF_HEADER_SIZE;

    mrvl_header_len = strlen(CMD_MARVELL) + strlen(PRIV_CMD_HOSTCMD);
    buf = (unsigned char *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);
    if (buf == NULL)
        return FAILURE;

    memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
    /* Fill up buffer */
    mrvl_cmd = (mrvl_priv_cmd *) buf;
    mrvl_cmd->buf = buf + sizeof(mrvl_priv_cmd);
    mrvl_cmd->used_len = 0;
    mrvl_cmd->total_len =
        MRVDRV_SIZE_OF_CMD_BUFFER - mrvl_header_len - BUF_HEADER_SIZE;
    /* Copy Marvell command string */
    temp = mrvl_cmd->buf;
    strncpy((char *) temp, CMD_MARVELL, strlen(CMD_MARVELL));
    temp += (strlen(CMD_MARVELL));
    /* Insert command string */
    strncpy((char *) temp, PRIV_CMD_HOSTCMD, strlen(PRIV_CMD_HOSTCMD));
    temp += (strlen(PRIV_CMD_HOSTCMD));

    memcpy(temp, (t_u8 *) cmd, *size);

    /* Initialize the ifr structure */
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_ifrn.ifrn_name, dev_name, IFNAMSIZ - 1);
    ifr.ifr_ifru.ifru_data = (void *) mrvl_cmd;
    header =
        (wifidirectcmdbuf *) (buf + sizeof(mrvl_priv_cmd) + mrvl_header_len);
    header->size = *size - BUF_HEADER_SIZE;
#ifdef DEBUG
    /* Debug print */
    hexdump(mrvl_cmd, *size + sizeof(mrvl_priv_cmd) + mrvl_header_len, ' ');
#endif
    endian_convert_request_header(header);

    /* Perform ioctl */
    errno = 0;
    if (ioctl(sockfd, MRVLPRIVCMD, &ifr)) {
        perror("");
        printf("ERR:MRVLPRIVCMD is not supported by %s\n", dev_name);
        ret = FAILURE;
        goto done;
    }
    endian_convert_response_header(header);
    header->cmd_code &= HostCmd_CMD_ID_MASK;
    header->cmd_code |= WIFIDIRECTCMD_RESP_CHECK;
    *size = header->size;
    memcpy(cmd, buf + sizeof(mrvl_priv_cmd) + mrvl_header_len,
           *size + BUF_HEADER_SIZE);
#ifdef DEBUG
    /* Debug print */
    hexdump(mrvl_cmd,
            *size + BUF_HEADER_SIZE + sizeof(mrvl_priv_cmd) + mrvl_header_len,
            ' ');
#endif

    /* Validate response size */
    if (*size > (buf_size - BUF_HEADER_SIZE)) {
        printf
            ("ERR:Response size (%d) greater than buffer size (%d)! Aborting!\n",
             *size, buf_size);
        ret = FAILURE;
        goto done;
    }
  done:
    /* Close socket */
    close(sockfd);
    if (buf)
        free(buf);
    return ret;
}

/**
 *  @brief Show usage information for the wifidirect_gas_comeback_discovery commands
 *
 *  $return         N/A
 */
static void
print_wifidirect_gas_comeback_usage(void)
{
    printf
        ("\nUsage : wifidirect_gas_comeback_request/response [CONFIG_FILE]\n");
    printf
        ("CONFIG_FILE contains WIFIDIRECT GAS comeback request/response payload.\n");
    return;
}

/** 
 *  @brief Creates a wifidirect_gas_comeback_service_discovery request/response and
 *         sends to the driver
 *
 *  Usage: "Usage : wifidirect_gas_comeback_request/response [CONFIG_FILE]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         SUCCESS or FAILURE
 **/
static void
wifidirectcmd_gas_comeback_discovery(int argc, char *argv[])
{
    wifidirect_gas_comeback_request *req_buf = NULL;
    wifidirect_gas_comeback_response *resp_buf = NULL;
    char *line = NULL;
    FILE *config_file = NULL;
    int i, opt, li = 0, arg_num = 0, ret = 0, wifidirect_level = 0;
    char *args[30], *pos = NULL, wifidirect_mac[20], wifidirect_cmd[40];
    t_u8 dev_address[ETH_ALEN], cmd_found = 0;
    t_u8 *buffer = NULL, *tmp_buffer = NULL;
    t_u8 req_resp = 0;          /* req = 0, resp = 1 */
    t_u16 cmd_len = 0, query_len = 0, vendor_len = 0, service_len = 0;
    t_u16 dns_len = 0, record_len = 0, upnp_len = 0;

    strncpy(wifidirect_cmd, argv[2], sizeof(wifidirect_cmd) - 1);
    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_gas_comeback_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if (argc != 3) {
        printf("ERR:Incorrect number of arguments.\n");
        print_wifidirect_gas_comeback_usage();
        return;
    }

    /* Check if file exists */
    config_file = fopen(argv[2], "r");
    if (config_file == NULL) {
        printf("\nERR:Config file can not open.\n");
        return;
    }
    line = (char *) malloc(MAX_CONFIG_LINE);
    if (!line) {
        printf("ERR:Cannot allocate memory for line\n");
        goto done;
    }
    memset(line, 0, MAX_CONFIG_LINE);

    /* Parse file and process */
    while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) {
        arg_num = parse_line(line, args);
        if (!cmd_found && strncmp(args[0], wifidirect_cmd, strlen(args[0])))
            continue;
        cmd_found = 1;

        if (strcmp(args[0], "wifidirect_gas_comeback_request") == 0) {
            wifidirect_level = WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE;
            /* For wifidirect_service_gas_comeback, basic initialization here */
            /* Subtract extra two bytes added as a part of query request
               structure */
            cmd_len = sizeof(wifidirect_gas_comeback_request) - 2;
            buffer = (t_u8 *) malloc(cmd_len);
            if (!buffer) {
                printf("ERR:Cannot allocate memory!\n");
                goto done;
            }
            req_buf = (wifidirect_gas_comeback_request *) buffer;
            req_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_SERVICE_DISCOVERY;
            req_buf->size = cmd_len;
            req_buf->seq_num = 0;
            req_buf->result = 0;

        } else if (strcmp(args[0], "wifidirect_gas_comeback_response") == 0) {
            wifidirect_level = WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE;
            req_resp = 1;
            /* For wifidirect_service_discovery, basic initialization here */
            /* Subtract extra two bytes added as a part of query response
               structure */
            cmd_len = sizeof(wifidirect_gas_comeback_response) - 2;
            buffer = (t_u8 *) malloc(cmd_len);
            if (!buffer) {
                printf("ERR:Cannot allocate memory!\n");
                goto done;
            }
            resp_buf = (wifidirect_gas_comeback_response *) buffer;
            resp_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_SERVICE_DISCOVERY;
            resp_buf->size = cmd_len;
            resp_buf->seq_num = 0;
            resp_buf->result = 0;

        } else if (strcmp(args[0], "PeerAddr") == 0) {
            strncpy(wifidirect_mac, args[1], 20);
            if ((ret = mac2raw(wifidirect_mac, dev_address)) != SUCCESS) {
                printf("ERR: %s Address \n",
                       ret == FAILURE ? "Invalid MAC" : ret ==
                       WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" :
                       "Multicast");
                goto done;
            }
            (!req_resp) ? memcpy(req_buf->peer_mac_addr, dev_address,
                                 ETH_ALEN) : memcpy(resp_buf->peer_mac_addr,
                                                    dev_address, ETH_ALEN);

        } else if (strcmp(args[0], "Category") == 0) {
            if (is_input_valid(WIFIDIRECT_CATEGORY, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;

            }
            (!req_resp) ? (req_buf->category = (t_u8) atoi(args[1])) :
                (resp_buf->category = (t_u8) atoi(args[1]));
        } else if (strcmp(args[0], "Action") == 0) {
            if (is_input_valid(WIFIDIRECT_ACTION, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            (!req_resp) ? (req_buf->action = (t_u8) A2HEXDECIMAL(args[1])) :
                (resp_buf->action = (t_u8) A2HEXDECIMAL(args[1]));
        } else if (strcmp(args[0], "DialogToken") == 0) {
            if (is_input_valid(WIFIDIRECT_DIALOGTOKEN, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            (!req_resp) ? (req_buf->dialog_taken = (t_u8) atoi(args[1])) :
                (resp_buf->dialog_taken = (t_u8) atoi(args[1]));
        } else if (strcmp(args[0], "StatusCode") == 0) {
            resp_buf->status_code = (t_u16) A2HEXDECIMAL(args[1]);
            resp_buf->status_code = cpu_to_le16(resp_buf->status_code);
        } else if (strcmp(args[0], "GasComebackDelay") == 0) {
            if (is_input_valid
                (WIFIDIRECT_GAS_COMEBACK_DELAY, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            resp_buf->gas_reply = (t_u16) A2HEXDECIMAL(args[1]);
            resp_buf->gas_reply = cpu_to_le16(resp_buf->gas_reply);
        } else if (strcmp(args[0], "GasResponseFragID") == 0) {
            resp_buf->gas_fragment_id = (t_u8) A2HEXDECIMAL(args[1]);
        } else if (strcmp(args[0], "AdvertizementProtocolIE") == 0) {
            if (is_input_valid(WIFIDIRECT_DISC_ADPROTOIE, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            for (i = 0; i < arg_num - 1; i++)
                resp_buf->advertize_protocol_ie[i] =
                    (t_u8) A2HEXDECIMAL(args[i + 1]);
        } else if (strcmp(args[0], "InfoId") == 0) {
            if (is_input_valid(WIFIDIRECT_DISC_INFOID, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            for (i = 0; i < arg_num - 1; i++)
                resp_buf->info_id[i] = (t_u8) A2HEXDECIMAL(args[i + 1]);
            query_len += arg_num - 1;
        } else if (strcmp(args[0], "OUI") == 0) {
            if (is_input_valid(WIFIDIRECT_OUI, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            for (i = 0; i < arg_num - 1; i++)
                resp_buf->oui[i] = (t_u8) A2HEXDECIMAL(args[i + 1]);
            service_len += arg_num - 1;
            query_len += arg_num - 1;
        } else if (strcmp(args[0], "OUISubType") == 0) {
            if (is_input_valid(WIFIDIRECT_OUISUBTYPE, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            resp_buf->oui_sub_type = (t_u8) atoi(args[1]);
            service_len++;
            query_len++;
        } else if (strcmp(args[0], "QueryRequestLen") == 0 ||
                   strcmp(args[0], "QueryResponseLen") == 0) {
            wifidirect_level = WIFIDIRECT_DISCOVERY_QUERY;
        } else if (strcmp(args[0], "RequestLen") == 0 ||
                   strcmp(args[0], "ResponseLen") == 0) {
            wifidirect_level = WIFIDIRECT_DISCOVERY_SERVICE;
            query_len += 2;
        } else if (strcmp(args[0], "VendorLen") == 0) {
            wifidirect_level = WIFIDIRECT_DISCOVERY_VENDOR;
            service_len += 2;
            query_len += 2;
        } else if (strcmp(args[0], "QueryData") == 0 ||
                   strcmp(args[0], "ResponseData") == 0) {
            wifidirect_level = WIFIDIRECT_DISCOVERY_QUERY_RESPONSE_PER_PROTOCOL;
        } else if (strcmp(args[0], "ServiceProtocol") == 0) {
            if (is_input_valid
                (WIFIDIRECT_DISC_SERVICEPROTO, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            resp_buf->service_protocol = (t_u8) atoi(args[1]);
            vendor_len++;
            service_len++;
            query_len++;
            /* 
             * For uPnP, due to union allocation, a extra byte is allocated 
             * reduce it here for uPnP
             */
            cmd_len--;
        } else if (strcmp(args[0], "ServiceUpdateIndicator") == 0) {
            if (is_input_valid
                (WIFIDIRECT_SERVICEUPDATE_INDICATOR, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            resp_buf->service_update_indicator =
                cpu_to_le16((t_u16) atoi(args[1]));
            service_len += 2;
            query_len += 2;
        } else if (strcmp(args[0], "ServiceTransactionId") == 0) {
            if (is_input_valid
                (WIFIDIRECT_DISC_SERVICETRANSACID, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            resp_buf->service_transaction_id = (t_u8) atoi(args[1]);
            vendor_len++;
            service_len++;
            query_len++;
        } else if (strcmp(args[0], "ServiceStatus") == 0) {
            if (is_input_valid
                (WIFIDIRECT_DISC_SERVICE_STATUS, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            resp_buf->disc_status_code = (t_u8) atoi(args[1]);
            vendor_len++;
            service_len++;
            query_len++;
        } else if (strcmp(args[0], "DNSName") == 0) {
            if (args[1][0] == '"') {
                args[1]++;
                if (args[1][strlen(args[1]) - 1] == '"')
                    args[1][strlen(args[1]) - 1] = '\0';

                dns_len = strlen(args[1]);
                tmp_buffer = realloc(buffer, cmd_len + dns_len);
                if (!tmp_buffer) {
                    printf("ERR:Cannot add DNS name to buffer!\n");
                    goto done;
                } else {
                    buffer = tmp_buffer;
                    tmp_buffer = NULL;
                }
                strncpy((char *) resp_buf->disc_resp.u.bonjour.dns, args[1],
                        strlen(args[1]));
            } else {
                /* HEX input */
                dns_len = arg_num - 1;
                tmp_buffer = realloc(buffer, cmd_len + dns_len);
                if (!tmp_buffer) {
                    printf("ERR:Cannot add DNS name to buffer!\n");
                    goto done;
                } else {
                    buffer = tmp_buffer;
                    tmp_buffer = NULL;
                }
                for (i = 0; i < arg_num - 1; i++)
                    resp_buf->disc_resp.u.bonjour.dns[i] =
                        (t_u8) A2HEXDECIMAL(args[i + 1]);
            }
            cmd_len += dns_len;
            vendor_len += dns_len;
            service_len += dns_len;
            query_len += dns_len;
        } else if (strcmp(args[0], "DNSType") == 0) {
            if (is_input_valid(WIFIDIRECT_DISC_DNSTYPE, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            *(&resp_buf->disc_resp.u.bonjour.dns_type + dns_len) =
                (t_u8) A2HEXDECIMAL(args[1]);
            vendor_len++;
            service_len++;
            query_len++;
        } else if (strcmp(args[0], "BonjourVersion") == 0) {
            if (is_input_valid
                (WIFIDIRECT_DISC_BONJOUR_VERSION, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            *(&resp_buf->disc_resp.u.bonjour.version + dns_len) =
                (t_u8) atoi(args[1]);
            vendor_len++;
            service_len++;
            query_len++;
        } else if (strcmp(args[0], "uPnPVersion") == 0) {
            if (is_input_valid
                (WIFIDIRECT_DISC_UPNP_VERSION, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            resp_buf->disc_resp.u.upnp.version = (t_u8) A2HEXDECIMAL(args[1]);
            vendor_len++;
            service_len++;
            query_len++;
        } else if (strcmp(args[0], "uPnPQueryValue") == 0 ||
                   strcmp(args[0], "uPnPResponseValue") == 0) {
            if (args[1][0] == '"') {
                args[1]++;
                if (args[1][strlen(args[1]) - 1] == '"')
                    args[1][strlen(args[1]) - 1] = '\0';

                upnp_len = strlen(args[1]);
                tmp_buffer = realloc(buffer, cmd_len + upnp_len);
                if (!tmp_buffer) {
                    printf("ERR:Cannot add uPnP value to buffer!\n");
                    goto done;
                } else {
                    buffer = tmp_buffer;
                    tmp_buffer = NULL;
                }
                strncpy((char *) resp_buf->disc_resp.u.upnp.value, args[1],
                        upnp_len);
            } else {
                /* HEX input */
                upnp_len = arg_num - 1;
                tmp_buffer = realloc(buffer, cmd_len + upnp_len);
                if (!tmp_buffer) {
                    printf("ERR:Cannot add uPnP value to buffer!\n");
                    goto done;
                } else {
                    buffer = tmp_buffer;
                    tmp_buffer = NULL;
                }
                for (i = 0; i < arg_num - 1; i++)
                    resp_buf->disc_resp.u.upnp.value[i] =
                        (t_u8) A2HEXDECIMAL(args[i + 1]);
            }
            cmd_len += upnp_len;
            vendor_len += upnp_len;
            service_len += upnp_len;
            query_len += upnp_len;
        } else if (strcmp(args[0], "RecordData") == 0) {
            if (args[1][0] == '"') {
                args[1]++;
                if (args[1][strlen(args[1]) - 1] == '"')
                    args[1][strlen(args[1]) - 1] = '\0';

                record_len = strlen(args[1]);
                tmp_buffer = realloc(buffer, cmd_len + record_len);
                if (!tmp_buffer) {
                    printf("ERR:Cannot add Record name to buffer!\n");
                    goto done;
                } else {
                    buffer = tmp_buffer;
                    tmp_buffer = NULL;
                }
                if (!req_resp) {
                    printf("ERR:Cannot add Record name to buffer!\n");
                    goto done;
                }
                strncpy((char *) resp_buf->disc_resp.u.bonjour.record, args[1],
                        strlen(args[1]));
            } else {
                /* HEX input */
                record_len = arg_num - 1;
                tmp_buffer = realloc(buffer, cmd_len + record_len);
                if (!tmp_buffer) {
                    printf("ERR:Cannot add Record name to buffer!\n");
                    goto done;
                } else {
                    buffer = tmp_buffer;
                    tmp_buffer = NULL;
                }
                if (!req_resp) {
                    printf("ERR:Cannot add Record name to buffer!\n");
                    goto done;
                }
                for (i = 0; i < arg_num - 1; i++)
                    resp_buf->disc_resp.u.bonjour.record[i] =
                        (t_u8) A2HEXDECIMAL(args[i + 1]);

            }
            cmd_len += record_len;
            vendor_len += record_len;
            service_len += record_len;
            query_len += record_len;
        } else if (strcmp(args[0], "}") == 0) {
            switch (wifidirect_level) {
            case WIFIDIRECT_DISCOVERY_QUERY:
                resp_buf->query_len = cpu_to_le16(query_len);
                break;
            case WIFIDIRECT_DISCOVERY_SERVICE:
                resp_buf->response_len = cpu_to_le16(service_len);
                break;
            case WIFIDIRECT_DISCOVERY_VENDOR:
                resp_buf->vendor_len = cpu_to_le16(vendor_len);
                break;
            default:
                break;
            }
            if (wifidirect_level) {
                if (wifidirect_level == WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE)
                    break;
                wifidirect_level--;
            }
        }
    }
    /* Send collective command */
    wifidirect_ioctl((t_u8 *) buffer, &cmd_len, cmd_len);
  done:
    fclose(config_file);
    if (buffer)
        free(buffer);
    if (line)
        free(line);
}

/**
 *  @brief Show usage information for the wifidirect_discovery commands
 *
 *  $return         N/A
 */
static void
print_wifidirect_discovery_usage(void)
{
    printf("\nUsage : wifidirect_discovery_request/response [CONFIG_FILE]\n");
    printf("CONFIG_FILE contains WIFIDIRECT service discovery payload.\n");
    return;
}

/** 
 *  @brief Creates a wifidirect_service_discovery request/response and
 *         sends to the driver
 *
 *  Usage: "Usage : wifidirect_discovery_request/response [CONFIG_FILE]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         SUCCESS or FAILURE
 **/
static void
wifidirectcmd_service_discovery(int argc, char *argv[])
{
    wifidirect_discovery_request *req_buf = NULL;
    wifidirect_discovery_response *resp_buf = NULL;
    char *line = NULL;
    FILE *config_file = NULL;
    int i, opt, li = 0, arg_num = 0, ret = 0, wifidirect_level = 0;
    char *args[30], *pos = NULL, wifidirect_mac[20], wifidirect_cmd[32];
    t_u8 dev_address[ETH_ALEN], cmd_found = 0;
    t_u8 *buffer = NULL, *tmp_buffer = NULL;
    t_u8 req_resp = 0;          /* req = 0, resp = 1 */
    t_u16 cmd_len = 0, query_len = 0, vendor_len = 0, service_len = 0;
    t_u16 dns_len = 0, record_len = 0, upnp_len = 0;

    strncpy(wifidirect_cmd, argv[2], sizeof(wifidirect_cmd) - 1);
    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_discovery_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if (argc != 3) {
        printf("ERR:Incorrect number of arguments.\n");
        print_wifidirect_discovery_usage();
        return;
    }

    /* Check if file exists */
    config_file = fopen(argv[2], "r");
    if (config_file == NULL) {
        printf("\nERR:Config file can not open.\n");
        return;
    }
    line = (char *) malloc(MAX_CONFIG_LINE);
    if (!line) {
        printf("ERR:Cannot allocate memory for line\n");
        goto done;
    }
    memset(line, 0, MAX_CONFIG_LINE);

    /* Parse file and process */
    while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) {
        arg_num = parse_line(line, args);
        if (!cmd_found && strncmp(args[0], wifidirect_cmd, strlen(args[0])))
            continue;
        cmd_found = 1;

        if (strcmp(args[0], "wifidirect_discovery_request") == 0) {
            wifidirect_level = WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE;
            /* For wifidirect_service_discovery, basic initialization here */
            cmd_len = sizeof(wifidirect_discovery_request);
            buffer = (t_u8 *) malloc(cmd_len);
            if (!buffer) {
                printf("ERR:Cannot allocate memory!\n");
                goto done;
            }
            req_buf = (wifidirect_discovery_request *) buffer;
            req_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_SERVICE_DISCOVERY;
            req_buf->size = cmd_len;
            req_buf->seq_num = 0;
            req_buf->result = 0;

        } else if (strcmp(args[0], "wifidirect_discovery_response") == 0) {
            wifidirect_level = WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE;
            req_resp = 1;
            /* For wifidirect_service_discovery, basic initialization here */
            cmd_len = sizeof(wifidirect_discovery_response);
            buffer = (t_u8 *) malloc(cmd_len);
            if (!buffer) {
                printf("ERR:Cannot allocate memory!\n");
                goto done;
            }
            resp_buf = (wifidirect_discovery_response *) buffer;
            resp_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_SERVICE_DISCOVERY;
            resp_buf->size = cmd_len;
            resp_buf->seq_num = 0;
            resp_buf->result = 0;

        } else if (strcmp(args[0], "PeerAddr") == 0) {
            strncpy(wifidirect_mac, args[1], 20 - 1);
            if ((ret = mac2raw(wifidirect_mac, dev_address)) != SUCCESS) {
                printf("ERR: %s Address \n",
                       ret == FAILURE ? "Invalid MAC" : ret ==
                       WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" :
                       "Multicast");
                goto done;
            }
            (!req_resp) ? memcpy(req_buf->peer_mac_addr, dev_address,
                                 ETH_ALEN) : memcpy(resp_buf->peer_mac_addr,
                                                    dev_address, ETH_ALEN);

        } else if (strcmp(args[0], "Category") == 0) {
            if (is_input_valid(WIFIDIRECT_CATEGORY, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;

            }
            (!req_resp) ? (req_buf->category = (t_u8) atoi(args[1])) :
                (resp_buf->category = (t_u8) atoi(args[1]));
        } else if (strcmp(args[0], "Action") == 0) {
            if (is_input_valid(WIFIDIRECT_ACTION, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            (!req_resp) ? (req_buf->action = (t_u8) A2HEXDECIMAL(args[1])) :
                (resp_buf->action = (t_u8) A2HEXDECIMAL(args[1]));
        } else if (strcmp(args[0], "DialogToken") == 0) {
            if (is_input_valid(WIFIDIRECT_DIALOGTOKEN, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            (!req_resp) ? (req_buf->dialog_taken = (t_u8) atoi(args[1])) :
                (resp_buf->dialog_taken = (t_u8) atoi(args[1]));
        } else if (strcmp(args[0], "StatusCode") == 0) {
            resp_buf->status_code = (t_u8) atoi(args[1]);
        } else if (strcmp(args[0], "GasComebackDelay") == 0) {
            if (is_input_valid
                (WIFIDIRECT_GAS_COMEBACK_DELAY, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            resp_buf->gas_reply = (t_u16) A2HEXDECIMAL(args[1]);
            resp_buf->gas_reply = cpu_to_le16(resp_buf->gas_reply);
        } else if (strcmp(args[0], "AdvertizementProtocolIE") == 0) {
            if (is_input_valid(WIFIDIRECT_DISC_ADPROTOIE, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            if (!req_resp) {
                for (i = 0; i < arg_num - 1; i++)
                    req_buf->advertize_protocol_ie[i] =
                        (t_u8) A2HEXDECIMAL(args[i + 1]);
            } else {
                for (i = 0; i < arg_num - 1; i++)
                    resp_buf->advertize_protocol_ie[i] =
                        (t_u8) A2HEXDECIMAL(args[i + 1]);
            }
        } else if (strcmp(args[0], "InfoId") == 0) {
            if (is_input_valid(WIFIDIRECT_DISC_INFOID, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            if (!req_resp) {
                for (i = 0; i < arg_num - 1; i++)
                    req_buf->info_id[i] = (t_u8) A2HEXDECIMAL(args[i + 1]);
            } else {
                for (i = 0; i < arg_num - 1; i++)
                    resp_buf->info_id[i] = (t_u8) A2HEXDECIMAL(args[i + 1]);
            }
            query_len += arg_num - 1;
        } else if (strcmp(args[0], "OUI") == 0) {
            if (is_input_valid(WIFIDIRECT_OUI, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            if (!req_resp) {
                for (i = 0; i < arg_num - 1; i++)
                    req_buf->oui[i] = (t_u8) A2HEXDECIMAL(args[i + 1]);
            } else {
                for (i = 0; i < arg_num - 1; i++)
                    resp_buf->oui[i] = (t_u8) A2HEXDECIMAL(args[i + 1]);
            }
            service_len += arg_num - 1;
            query_len += arg_num - 1;
        } else if (strcmp(args[0], "OUISubType") == 0) {
            if (is_input_valid(WIFIDIRECT_OUISUBTYPE, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            (!req_resp) ? (req_buf->oui_sub_type = (t_u8) atoi(args[1])) :
                (resp_buf->oui_sub_type = (t_u8) atoi(args[1]));
            service_len++;
            query_len++;
        } else if (strcmp(args[0], "QueryRequestLen") == 0 ||
                   strcmp(args[0], "QueryResponseLen") == 0) {
            wifidirect_level = WIFIDIRECT_DISCOVERY_QUERY;
        } else if (strcmp(args[0], "RequestLen") == 0 ||
                   strcmp(args[0], "ResponseLen") == 0) {
            wifidirect_level = WIFIDIRECT_DISCOVERY_SERVICE;
            query_len += 2;
        } else if (strcmp(args[0], "VendorLen") == 0) {
            wifidirect_level = WIFIDIRECT_DISCOVERY_VENDOR;
            service_len += 2;
            query_len += 2;
        } else if (strcmp(args[0], "QueryData") == 0 ||
                   strcmp(args[0], "ResponseData") == 0) {
            wifidirect_level = WIFIDIRECT_DISCOVERY_QUERY_RESPONSE_PER_PROTOCOL;
        } else if (strcmp(args[0], "ServiceProtocol") == 0) {
            if (is_input_valid
                (WIFIDIRECT_DISC_SERVICEPROTO, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            if (!req_resp) {
                req_buf->service_protocol = (t_u8) atoi(args[1]);
                /* 
                 * For uPnP, due to union allocation, a extra byte
                 * is allocated reduce it here for uPnP
                 */
                if (req_buf->service_protocol == 2)
                    cmd_len--;
            } else {
                resp_buf->service_protocol = (t_u8) atoi(args[1]);
                if (resp_buf->service_protocol == 2)
                    cmd_len--;
            }
            vendor_len++;
            service_len++;
            query_len++;
        } else if (strcmp(args[0], "ServiceUpdateIndicator") == 0) {
            if (is_input_valid
                (WIFIDIRECT_SERVICEUPDATE_INDICATOR, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            (!req_resp) ? (req_buf->service_update_indicator =
                           cpu_to_le16((t_u16) atoi(args[1]))) :
                (resp_buf->service_update_indicator =
                 cpu_to_le16((t_u16) atoi(args[1])));
            service_len += 2;
            query_len += 2;
        } else if (strcmp(args[0], "ServiceTransactionId") == 0) {
            if (is_input_valid
                (WIFIDIRECT_DISC_SERVICETRANSACID, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            (!req_resp) ? (req_buf->service_transaction_id =
                           (t_u8) atoi(args[1])) : (resp_buf->
                                                    service_transaction_id =
                                                    (t_u8) atoi(args[1]));
            vendor_len++;
            service_len++;
            query_len++;
        } else if (strcmp(args[0], "ServiceStatus") == 0) {
            if (is_input_valid
                (WIFIDIRECT_DISC_SERVICE_STATUS, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            resp_buf->disc_status_code = (t_u8) atoi(args[1]);
            vendor_len++;
            service_len++;
            query_len++;
        } else if (strcmp(args[0], "DNSName") == 0) {
            if (args[1][0] == '"') {
                args[1]++;
                if (args[1][strlen(args[1]) - 1] == '"')
                    args[1][strlen(args[1]) - 1] = '\0';

                dns_len = strlen(args[1]);
                tmp_buffer = realloc(buffer, cmd_len + dns_len);
                if (!tmp_buffer) {
                    printf("ERR:Cannot add DNS name to buffer!\n");
                    goto done;
                } else {
                    buffer = tmp_buffer;
                    tmp_buffer = NULL;
                }
                (!req_resp) ?
                    (strncpy
                     ((char *) req_buf->disc_query.u.bonjour.dns, args[1],
                      strlen(args[1]))) : (strncpy((char *) resp_buf->disc_resp.
                                                   u.bonjour.dns, args[1],
                                                   strlen(args[1])));
            } else {
                /* HEX input */
                dns_len = arg_num - 1;
                tmp_buffer = realloc(buffer, cmd_len + dns_len);
                if (!tmp_buffer) {
                    printf("ERR:Cannot add DNS name to buffer!\n");
                    goto done;
                } else {
                    buffer = tmp_buffer;
                    tmp_buffer = NULL;
                }
                if (!req_resp) {
                    for (i = 0; i < arg_num - 1; i++)
                        req_buf->disc_query.u.bonjour.dns[i] =
                            (t_u8) A2HEXDECIMAL(args[i + 1]);
                } else {
                    for (i = 0; i < arg_num - 1; i++)
                        resp_buf->disc_resp.u.bonjour.dns[i] =
                            (t_u8) A2HEXDECIMAL(args[i + 1]);
                }
            }
            cmd_len += dns_len;
            vendor_len += dns_len;
            service_len += dns_len;
            query_len += dns_len;
        } else if (strcmp(args[0], "DNSType") == 0) {
            if (is_input_valid(WIFIDIRECT_DISC_DNSTYPE, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            (!req_resp) ?
                (*(&req_buf->disc_query.u.bonjour.dns_type + dns_len) =
                 (t_u8) A2HEXDECIMAL(args[1])) :
                (*(&resp_buf->disc_resp.u.bonjour.dns_type + dns_len) =
                 (t_u8) A2HEXDECIMAL(args[1]));
            vendor_len++;
            service_len++;
            query_len++;
        } else if (strcmp(args[0], "BonjourVersion") == 0) {
            if (is_input_valid
                (WIFIDIRECT_DISC_BONJOUR_VERSION, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            (!req_resp) ?
                (*(&req_buf->disc_query.u.bonjour.version + dns_len) =
                 (t_u8) atoi(args[1])) :
                (*(&resp_buf->disc_resp.u.bonjour.version + dns_len) =
                 (t_u8) atoi(args[1]));
            vendor_len++;
            service_len++;
            query_len++;
        } else if (strcmp(args[0], "uPnPVersion") == 0) {
            if (is_input_valid
                (WIFIDIRECT_DISC_UPNP_VERSION, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            (!req_resp) ?
                (req_buf->disc_query.u.upnp.version =
                 (t_u8) A2HEXDECIMAL(args[1])) : (resp_buf->disc_resp.u.upnp.
                                                  version =
                                                  (t_u8) A2HEXDECIMAL(args[1]));
            vendor_len++;
            service_len++;
            query_len++;
        } else if (strcmp(args[0], "uPnPQueryValue") == 0 ||
                   strcmp(args[0], "uPnPResponseValue") == 0) {
            if (args[1][0] == '"') {
                args[1]++;
                if (args[1][strlen(args[1]) - 1] == '"')
                    args[1][strlen(args[1]) - 1] = '\0';

                upnp_len = strlen(args[1]);
                tmp_buffer = realloc(buffer, cmd_len + upnp_len);
                if (!tmp_buffer) {
                    printf("ERR:Cannot add uPnP value to buffer!\n");
                    goto done;
                } else {
                    buffer = tmp_buffer;
                    tmp_buffer = NULL;
                }
                (!req_resp) ?
                    (strncpy((char *) req_buf->disc_query.u.upnp.value, args[1],
                             upnp_len)) :
                    (strncpy((char *) resp_buf->disc_resp.u.upnp.value, args[1],
                             upnp_len));
            } else {
                /* HEX input */
                upnp_len = arg_num - 1;
                tmp_buffer = realloc(buffer, cmd_len + upnp_len);
                if (!tmp_buffer) {
                    printf("ERR:Cannot add uPnP value to buffer!\n");
                    goto done;
                } else {
                    buffer = tmp_buffer;
                    tmp_buffer = NULL;
                }
                if (!req_resp) {
                    for (i = 0; i < arg_num - 1; i++)
                        req_buf->disc_query.u.upnp.value[i] =
                            (t_u8) A2HEXDECIMAL(args[i + 1]);
                } else {
                    for (i = 0; i < arg_num - 1; i++)
                        resp_buf->disc_resp.u.upnp.value[i] =
                            (t_u8) A2HEXDECIMAL(args[i + 1]);
                }
            }
            cmd_len += upnp_len;
            vendor_len += upnp_len;
            service_len += upnp_len;
            query_len += upnp_len;
        } else if (strcmp(args[0], "RecordData") == 0) {
            if (args[1][0] == '"') {
                args[1]++;
                if (args[1][strlen(args[1]) - 1] == '"')
                    args[1][strlen(args[1]) - 1] = '\0';

                record_len = strlen(args[1]);
                tmp_buffer = realloc(buffer, cmd_len + record_len);
                if (!tmp_buffer) {
                    printf("ERR:Cannot add Record name to buffer!\n");
                    goto done;
                } else {
                    buffer = tmp_buffer;
                    tmp_buffer = NULL;
                }
                if (!req_resp) {
                    printf("ERR:Cannot add Record name to buffer!\n");
                    goto done;
                }
                strncpy((char *) resp_buf->disc_resp.u.bonjour.record + dns_len,
                        args[1], strlen(args[1]));
            } else {
                /* HEX input */
                record_len = arg_num - 1;
                tmp_buffer = realloc(buffer, cmd_len + record_len);
                if (!tmp_buffer) {
                    printf("ERR:Cannot add Record name to buffer!\n");
                    goto done;
                } else {
                    buffer = tmp_buffer;
                    tmp_buffer = NULL;
                }
                if (!req_resp) {
                    printf("ERR:Cannot add Record name to buffer!\n");
                    goto done;
                }
                for (i = 0; i < arg_num - 1; i++)
                    *(&resp_buf->disc_resp.u.bonjour.record[i] + dns_len) =
                        (t_u8) A2HEXDECIMAL(args[i + 1]);
            }
            cmd_len += record_len;
            vendor_len += record_len;
            service_len += record_len;
            query_len += record_len;
        } else if (strcmp(args[0], "}") == 0) {
            switch (wifidirect_level) {
            case WIFIDIRECT_DISCOVERY_QUERY:
                (!req_resp) ? (req_buf->query_len = cpu_to_le16(query_len)) :
                    (resp_buf->query_len = cpu_to_le16(query_len));
                break;
            case WIFIDIRECT_DISCOVERY_SERVICE:
                (!req_resp) ? (req_buf->request_len =
                               cpu_to_le16(service_len)) : (resp_buf->
                                                            response_len =
                                                            cpu_to_le16
                                                            (service_len));
                break;
            case WIFIDIRECT_DISCOVERY_VENDOR:
                (!req_resp) ? (req_buf->vendor_len = cpu_to_le16(vendor_len)) :
                    (resp_buf->vendor_len = cpu_to_le16(vendor_len));
                break;
            default:
                break;
            }
            if (wifidirect_level) {
                if (wifidirect_level == WIFIDIRECT_DISCOVERY_REQUEST_RESPONSE)
                    break;
                wifidirect_level--;
            }
        }
    }
    /* Send collective command */
    wifidirect_ioctl((t_u8 *) buffer, &cmd_len, cmd_len);
  done:
    fclose(config_file);
    if (buffer)
        free(buffer);
    if (line)
        free(line);
}

/**
 *  @brief Show usage information for the wifidirect_config command
 *
 *  $return         N/A
 */
static void
print_wifidirect_config_usage(void)
{
    printf("\nUsage : wifidirect_config [CONFIG_FILE]\n");
    printf
        ("\nIf CONFIG_FILE is provided, a 'set' is performed, else a 'get' is performed.\n");
    printf("CONFIG_FILE contains all WIFIDIRECT parameters.\n");
    return;
}

/** 
 *  @brief Read the wifidirect parameters and sends to the driver
 *
 *  @param file_name File to open for configuration parameters. 
 *  @param cmd_name  Command Name for which parameters are read.
 *  @param pbuf      Pointer to output buffer
 *  @param ie_len_wifidirect Length of wifidirect parameters to return 
 *  @param ie_len_wps Length of WPS parameters to return 
 *  @return          SUCCESS or FAILURE
 */
static const t_u8 wifidirect_oui[] = { 0x50, 0x6F, 0x9A, 0x09 };
static const t_u8 wps_oui[] = { 0x00, 0x50, 0xF2, 0x04 };

static void
wifidirect_file_params_config(char *file_name, char *cmd_name, t_u8 * pbuf,
                              t_u16 * ie_len_wifidirect, t_u16 * ie_len_wps)
{
    FILE *config_file = NULL;
    char *line = NULL;
    int i = 0, li = 0, arg_num = 0, ret = 0, wifidirect_level =
        0, no_of_chan_entries = 0, no_of_noa = 0;
    int secondary_index = -1, flag = 1, group_secondary_index = -1;
    char **args = NULL;
    char *pos = NULL;
    char wifidirect_mac[20], country[4], wifidirect_ssid[33];
    char WPS_manufacturer[33], WPS_modelname[33], WPS_devicename[33],
        wifi_group_direct_ssid[33];
    t_u8 dev_channels[MAX_CHANNELS];
    t_u8 iface_list[ETH_ALEN * MAX_INTERFACE_ADDR_COUNT];
    t_u8 dev_address[ETH_ALEN];
    t_u8 group_dev_address[ETH_ALEN];
    t_u8 *extra = NULL;
    t_u8 *buffer = pbuf;
    t_u16 cmd_len_wifidirect = 0, cmd_len_wps = 0, tlv_len = 0, extra_len =
        0, temp = 0;
    t_u16 wps_model_len = 0, wps_serial_len = 0;
    t_u16 pri_category = 0, pri_sub_category = 0, config_methods = 0;
    t_u16 sec_category = 0, sec_sub_category = 0, group_sec_sub_category =
        0, group_sec_category = 0;
    t_u16 avail_period = 0, avail_interval = 0;
    t_u8 secondary_oui[4], group_secondary_oui[4];
    t_u16 WPS_specconfigmethods = 0, WPS_associationstate = 0,
        WPS_configurationerror = 0, WPS_devicepassword = 0;
    t_u8 dev_capability = 0, group_capability = 0, cmd_found = 0,
        group_owner_intent = 0, primary_oui[4], iface_count = 0,
        regulatory_class = 0, channel_number = 0, manageability = 0,
        op_regulatory_class = 0, op_channel_number = 0, invitation_flag = 0;
    t_u8 WPS_version = 0, WPS_setupstate = 0, WPS_requesttype =
        0, WPS_responsetype =
        0, WPS_UUID[WPS_UUID_MAX_LEN],
        WPS_primarydevicetype[WPS_DEVICE_TYPE_MAX_LEN], WPS_RFband =
        0, WPS_modelnumber[4], WPS_serialnumber[4];
    t_u8 go_config_timeout = 0, client_config_timeout = 0;
    t_u8 secondary_dev_count = 0, group_secondary_dev_count = 0;
    t_u16 temp16 = 0;
    t_u8 secondary_dev_info[WPS_DEVICE_TYPE_LEN * MAX_SECONDARY_DEVICE_COUNT];
    t_u8 group_secondary_dev_info[WPS_DEVICE_TYPE_LEN *
                                  MAX_GROUP_SECONDARY_DEVICE_COUNT];
    t_u8 wifidirect_client_dev_count = 0, wifidirect_client_dev_index =
        0, temp8 = 0;
    wifidirect_client_dev_info
        wifidirect_client_dev_info_list[MAX_SECONDARY_DEVICE_COUNT];
    t_u8 wifidirect_secondary_dev_count =
        0, wifidirect_total_secondary_dev_count = 0;
    t_u8 wifidirect_group_total_ssid_len = 0, tlv_offset = 0, temp_dev_size = 0;
    t_u8 noa_index = 0, opp_ps = 0, ctwindow_opp_ps = 0, count_type = 0;
    t_u32 duration = 0, interval = 0, start_time = 0;
    t_u16 total_chan_len = 0;
    t_u8 chan_entry_regulatory_class = 0, chan_entry_num_of_channels = 0;
    t_u8 *chan_entry_list = NULL;
    t_u8 *chan_buf = NULL;
    noa_descriptor noa_descriptor_list[MAX_NOA_DESCRIPTORS];
    /* Check if file exists */
    config_file = fopen(file_name, "r");
    if (config_file == NULL) {
        printf("\nERR:Config file can not open.\n");
        return;
    }

    /* Memory allocations */
    line = (char *) malloc(MAX_CONFIG_LINE);
    if (!line) {
        printf("ERR:Cannot allocate memory for line\n");
        goto done;
    }
    memset(line, 0, MAX_CONFIG_LINE);

    extra = (t_u8 *) malloc(MAX_CONFIG_LINE);
    if (!extra) {
        printf("ERR:Cannot allocate memory for extra\n");
        goto done;
    }
    memset(extra, 0, MAX_CONFIG_LINE);

    args = (char **) malloc(sizeof(char *) * MAX_ARGS_NUM);
    if (!args) {
        printf("ERR:Cannot allocate memory for args\n");
        goto done;
    }
    memset(args, 0, (sizeof(char *) * MAX_ARGS_NUM));

    if (!wifidir_use_fixed_ie_indices()) {
        special_mask_custom_ie_buf *wifidirect_ie_buf;
        wifidirect_ie_buf = (special_mask_custom_ie_buf *) buffer;
        memcpy(&wifidirect_ie_buf->Oui[0], wifidirect_oui,
               sizeof(wifidirect_oui));
        cmd_len_wifidirect += sizeof(wifidirect_oui);
    }
    /* Parse file and process */
    while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) {
        arg_num = parse_line(line, args);
        if (!cmd_found && strncmp(args[0], cmd_name, strlen(args[0])))
            continue;
        cmd_found = 1;
        if (strcmp(args[0], "wifidirect_config") == 0) {
            wifidirect_level = WIFIDIRECT_PARAMS_CONFIG;
        } else if (strcmp(args[0], "Capability") == 0) {
            wifidirect_level = WIFIDIRECT_CAPABILITY_CONFIG;
        } else if (strcmp(args[0], "GroupOwnerIntent") == 0) {
            wifidirect_level = WIFIDIRECT_GROUP_OWNER_INTENT_CONFIG;
        } else if (strcmp(args[0], "Channel") == 0) {
            wifidirect_level = WIFIDIRECT_CHANNEL_CONFIG;
        } else if (strcmp(args[0], "OperatingChannel") == 0) {
            wifidirect_level = WIFIDIRECT_OPCHANNEL_CONFIG;
        } else if (strcmp(args[0], "InfrastructureManageabilityInfo") == 0) {
            wifidirect_level = WIFIDIRECT_MANAGEABILITY_CONFIG;
        } else if (strcmp(args[0], "InvitationFlagBitmap") == 0) {
            wifidirect_level = WIFIDIRECT_INVITATION_FLAG_CONFIG;
        } else if (strcmp(args[0], "ChannelList") == 0) {
            wifidirect_level = WIFIDIRECT_CHANNEL_LIST_CONFIG;
        } else if (strcmp(args[0], "NoticeOfAbsence") == 0) {
            wifidirect_level = WIFIDIRECT_NOTICE_OF_ABSENCE;
        } else if (strcmp(args[0], "NoA_descriptor") == 0) {
            wifidirect_level = WIFIDIRECT_NOA_DESCRIPTOR;
        } else if (strcmp(args[0], "DeviceInfo") == 0) {
            wifidirect_level = WIFIDIRECT_DEVICE_INFO_CONFIG;
        } else if (strcmp(args[0], "SecondaryDeviceType") == 0) {
            wifidirect_level = WIFIDIRECT_DEVICE_SEC_INFO_CONFIG;
        } else if (strcmp(args[0], "GroupInfo") == 0) {
            wifidirect_level = WIFIDIRECT_GROUP_INFO_CONFIG;
        } else if (strcmp(args[0], "GroupSecondaryDeviceTypes") == 0) {
            wifidirect_level = WIFIDIRECT_GROUP_SEC_INFO_CONFIG;
        } else if (strcmp(args[0], "GroupWifiDirectDeviceTypes") == 0) {
            wifidirect_level = WIFIDIRECT_GROUP_CLIENT_INFO_CONFIG;
        } else if (strcmp(args[0], "GroupId") == 0) {
            wifidirect_level = WIFIDIRECT_GROUP_ID_CONFIG;
        } else if (strcmp(args[0], "GroupBSSId") == 0) {
            wifidirect_level = WIFIDIRECT_GROUP_BSS_ID_CONFIG;
        } else if (strcmp(args[0], "DeviceId") == 0) {
            wifidirect_level = WIFIDIRECT_DEVICE_ID_CONFIG;
        } else if (strcmp(args[0], "Interface") == 0) {
            wifidirect_level = WIFIDIRECT_INTERFACE_CONFIG;
        } else if (strcmp(args[0], "ConfigurationTimeout") == 0) {
            wifidirect_level = WIFIDIRECT_TIMEOUT_CONFIG;
        } else if (strcmp(args[0], "ExtendedListenTime") == 0) {
            wifidirect_level = WIFIDIRECT_EXTENDED_TIME_CONFIG;
        } else if (strcmp(args[0], "IntendedIntfAddress") == 0) {
            wifidirect_level = WIFIDIRECT_INTENDED_ADDR_CONFIG;
        } else if (strcmp(args[0], "WPSIE") == 0) {
            wifidirect_level = WIFIDIRECT_WPSIE;
        } else if (strcmp(args[0], "Extra") == 0) {
            wifidirect_level = WIFIDIRECT_EXTRA;
        } else if (strcmp(args[0], "WIFIDIRECT_MAC") == 0 ||
                   strcmp(args[0], "GroupAddr") == 0 ||
                   strcmp(args[0], "GroupBssId") == 0 ||
                   strcmp(args[0], "InterfaceAddress") == 0 ||
                   strcmp(args[0], "GroupInterfaceAddress") == 0 ||
                   strcmp(args[0], "DeviceAddress") == 0) {
            strncpy(wifidirect_mac, args[1], 20 - 1);
            if ((ret = mac2raw(wifidirect_mac, dev_address)) != SUCCESS) {
                printf("ERR: %s Address \n",
                       ret == FAILURE ? "Invalid MAC" : ret ==
                       WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" :
                       "Multicast");
                goto done;
            }
        } else if (strncmp(args[0], "GroupWifiDirectDeviceAddress", 21) == 0) {
            strncpy(wifidirect_mac, args[1], 20 - 1);
            if ((ret = mac2raw(wifidirect_mac, group_dev_address)) != SUCCESS) {
                printf("ERR: %s Address \n",
                       ret == FAILURE ? "Invalid MAC" : ret ==
                       WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" :
                       "Multicast");
                goto done;
            }
            wifidirect_client_dev_index++;
            if (wifidirect_client_dev_index > wifidirect_client_dev_count) {
                printf
                    ("ERR: No of Client Dev count is less than no of client dev configs!!\n");
                goto done;
            }
            group_secondary_index = 0;
            wifidirect_secondary_dev_count = 0;
            tlv_offset =
                wifidirect_group_total_ssid_len +
                wifidirect_total_secondary_dev_count * WPS_DEVICE_TYPE_LEN;
            memcpy(wifidirect_client_dev_info_list
                   [wifidirect_client_dev_index - 1].wifidirect_dev_address +
                   tlv_offset, group_dev_address, ETH_ALEN);
        } else if (strncmp(args[0], "GroupWifiDirectIntfAddress", 19) == 0) {
            strncpy(wifidirect_mac, args[1], 20 - 1);
            if ((ret = mac2raw(wifidirect_mac, group_dev_address)) != SUCCESS) {
                printf("ERR: %s Address \n",
                       ret == FAILURE ? "Invalid MAC" : ret ==
                       WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" :
                       "Multicast");
                goto done;
            }
            memcpy(wifidirect_client_dev_info_list
                   [wifidirect_client_dev_index - 1].wifidirect_intf_address +
                   tlv_offset, group_dev_address, ETH_ALEN);
        } else if (strncmp(args[0], "GroupWifiDirectDeviceCapab", 19) == 0) {
            if (is_input_valid
                (WIFIDIRECT_DEVICECAPABILITY, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            temp8 = (t_u8) atoi(args[1]);
            memcpy(&wifidirect_client_dev_info_list
                   [wifidirect_client_dev_index - 1].wifidirect_dev_capability +
                   tlv_offset, &temp8, sizeof(temp8));
        } else if (strncmp(args[0], "GroupWifiDirectWPSConfigMethods", 24) == 0) {
            if (is_input_valid(WIFIDIRECT_WPSCONFMETHODS, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            temp16 = (t_u16) A2HEXDECIMAL(args[1]);
            memcpy(&wifidirect_client_dev_info_list
                   [wifidirect_client_dev_index - 1].config_methods +
                   tlv_offset, &temp16, sizeof(temp16));
            (t_u16) A2HEXDECIMAL(args[1]);
        } else if (strncmp(args[0], "GroupPrimaryDeviceTypeCategory", 30) == 0) {
            if (is_input_valid
                (WIFIDIRECT_PRIDEVTYPECATEGORY, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            pri_category = (t_u16) atoi(args[1]);
            temp16 = htons(pri_category);
            memcpy(&wifidirect_client_dev_info_list
                   [wifidirect_client_dev_index - 1].primary_category +
                   tlv_offset, &temp16, sizeof(temp16));
        } else if (strncmp(args[0], "GroupPrimaryDeviceTypeOUI", 25) == 0) {
            if (is_input_valid(WIFIDIRECT_PRIDEVTYPEOUI, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            for (i = 0; i < 4; i++) {
                temp8 = (t_u8) A2HEXDECIMAL(args[i + 1]);
                memcpy(&wifidirect_client_dev_info_list
                       [wifidirect_client_dev_index - 1].primary_oui[i]
                       + tlv_offset, &temp8, sizeof(temp8));
            }
        } else if (strncmp(args[0], "GroupPrimaryDeviceTypeSubCategory", 33) ==
                   0) {
            if (is_input_valid
                (WIFIDIRECT_PRIDEVTYPESUBCATEGORY, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            pri_sub_category = (t_u16) atoi(args[1]);
            temp16 = htons(pri_sub_category);
            memcpy(&wifidirect_client_dev_info_list
                   [wifidirect_client_dev_index - 1].primary_subcategory +
                   tlv_offset, &temp16, sizeof(temp16));
        } else if (strncmp(args[0], "GroupSecondaryDeviceCount", 25) == 0) {
            if (is_input_valid
                (WIFIDIRECT_GROUP_SECONDARYDEVCOUNT, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            group_secondary_dev_count = (t_u8) atoi(args[1]);
            memcpy(&wifidirect_client_dev_info_list
                   [wifidirect_client_dev_index -
                    1].wifidirect_secondary_dev_count + tlv_offset,
                   &group_secondary_dev_count,
                   sizeof(group_secondary_dev_count));
            wifidirect_total_secondary_dev_count += group_secondary_dev_count;
            if (group_secondary_dev_count)
                memset(group_secondary_dev_info, 0,
                       sizeof(group_secondary_dev_info));
        } else if (strncmp(args[0], "GroupSecondaryDeviceTypeCategory", 30) ==
                   0) {
            if (is_input_valid
                (WIFIDIRECT_PRIDEVTYPECATEGORY, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            sec_category = (t_u16) atoi(args[1]);
            group_sec_category = cpu_to_le16(sec_category);
            group_secondary_index++;
        } else if (strncmp(args[0], "GroupSecondaryDeviceTypeOUI", 27) == 0) {
            if (is_input_valid(WIFIDIRECT_PRIDEVTYPEOUI, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            for (i = 0; i < 4; i++)
                group_secondary_oui[i] = (t_u8) A2HEXDECIMAL(args[i + 1]);
        } else if (strncmp(args[0], "GroupSecondaryDeviceTypeSubCategory", 35)
                   == 0) {
            if (is_input_valid
                (WIFIDIRECT_PRIDEVTYPESUBCATEGORY, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            if (group_secondary_index < 0 ||
                group_secondary_index >= MAX_SECONDARY_DEVICE_COUNT) {
                printf("Error in configuration file %s:%d", file_name, li);
                goto done;
            }
            sec_sub_category = (t_u16) atoi(args[1]);
            group_sec_sub_category = cpu_to_le16(group_sec_sub_category);
            if (group_secondary_dev_count) {
                memcpy(&group_secondary_dev_info
                       [(group_secondary_index - 1) * WPS_DEVICE_TYPE_LEN],
                       &group_sec_category, sizeof(t_u16));
                memcpy(&group_secondary_dev_info
                       [((group_secondary_index - 1) * WPS_DEVICE_TYPE_LEN) +
                        2], group_secondary_oui, sizeof(secondary_oui));
                memcpy(&group_secondary_dev_info
                       [((group_secondary_index - 1) * WPS_DEVICE_TYPE_LEN) +
                        6], &group_sec_sub_category, sizeof(t_u16));
            }

        } else if (strncmp(args[0], "GroupWifiDirectDeviceCount", 19) == 0) {
            if (is_input_valid
                (WIFIDIRECT_SECONDARYDEVCOUNT, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            wifidirect_client_dev_count = (t_u8) atoi(args[1]);
        } else if (strncmp(args[0], "GroupWifiDirectDeviceName", 18) == 0) {

            if (is_input_valid
                (WIFIDIRECT_GROUP_WIFIDIRECT_DEVICE_NAME, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }

            strncpy(wifi_group_direct_ssid, args[1] + 1, strlen(args[1]) - 2);
            wifi_group_direct_ssid[strlen(args[1]) - 2] = '\0';
            temp = htons(SC_Device_Name);
            memcpy(((t_u8 *) &
                    wifidirect_client_dev_info_list[wifidirect_client_dev_index
                                                    -
                                                    1].
                    wifidirect_device_name_type + tlv_offset), &temp,
                   sizeof(temp));
            temp = htons(strlen(wifi_group_direct_ssid));
            memcpy(((t_u8 *) &
                    wifidirect_client_dev_info_list[wifidirect_client_dev_index
                                                    -
                                                    1].
                    wifidirect_device_name_len + tlv_offset), &temp,
                   sizeof(temp));
            memset(((t_u8 *) &
                    wifidirect_client_dev_info_list[wifidirect_client_dev_index
                                                    -
                                                    1].wifidirect_device_name +
                    tlv_offset), 0, strlen(wifi_group_direct_ssid));
            memcpy(((t_u8 *) &
                    wifidirect_client_dev_info_list[wifidirect_client_dev_index
                                                    -
                                                    1].wifidirect_device_name +
                    tlv_offset), &wifi_group_direct_ssid,
                   strlen(wifi_group_direct_ssid));
            wifidirect_group_total_ssid_len += strlen(wifi_group_direct_ssid);

            if (wifidirect_client_dev_index - 1) {
                temp_dev_size =
                    sizeof(wifidirect_client_dev_info) +
                    strlen(wifi_group_direct_ssid) +
                    group_secondary_dev_count * WPS_DEVICE_TYPE_LEN;
                memcpy(&wifidirect_client_dev_info_list
                       [wifidirect_client_dev_index - 1].dev_length +
                       (tlv_offset -
                        (group_secondary_dev_count * WPS_DEVICE_TYPE_LEN)),
                       &temp_dev_size, sizeof(temp_dev_size));
            } else {

                temp_dev_size =
                    sizeof(wifidirect_client_dev_info) +
                    strlen(wifi_group_direct_ssid) +
                    group_secondary_dev_count * WPS_DEVICE_TYPE_LEN;
                wifidirect_client_dev_info_list[wifidirect_client_dev_index -
                                                1].dev_length =
                    sizeof(wifidirect_client_dev_info) +
                    strlen(wifi_group_direct_ssid) +
                    group_secondary_dev_count * WPS_DEVICE_TYPE_LEN;
            }
        } else if (strcmp(args[0], "DeviceCapability") == 0) {
            if (is_input_valid
                (WIFIDIRECT_DEVICECAPABILITY, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            dev_capability = (t_u8) atoi(args[1]);
        } else if (strcmp(args[0], "GroupCapability") == 0) {
            if (is_input_valid
                (WIFIDIRECT_GROUPCAPABILITY, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            group_capability = (t_u8) atoi(args[1]);
        } else if (strcmp(args[0], "Intent") == 0) {
            /* Intent -> 0 - 15 */
            if (is_input_valid(WIFIDIRECT_INTENT, arg_num - 1, args + 1) !=
                SUCCESS) {
                goto done;
            }
            group_owner_intent = (t_u8) atoi(args[1]);
        } else if (strcmp(args[0], "RegulatoryClass") == 0) {
            if (is_input_valid
                (WIFIDIRECT_REGULATORYCLASS, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            regulatory_class = (t_u8) atoi(args[1]);
        } else if (strcmp(args[0], "ChannelNumber") == 0) {
            if (is_input_valid(CHANNEL, arg_num - 1, args + 1) != SUCCESS) {
                goto done;
            }
            channel_number = (t_u8) atoi(args[1]);
        } else if (strcmp(args[0], "OpRegulatoryClass") == 0) {
            if (is_input_valid
                (WIFIDIRECT_REGULATORYCLASS, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            op_regulatory_class = (t_u8) atoi(args[1]);
        } else if (strcmp(args[0], "OpChannelNumber") == 0) {
            if (is_input_valid(CHANNEL, arg_num - 1, args + 1) != SUCCESS) {
                goto done;
            }
            op_channel_number = (t_u8) atoi(args[1]);
        } else if (strcmp(args[0], "Manageability") == 0) {
            if (is_input_valid(WIFIDIRECT_MANAGEABILITY, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            manageability = (t_u8) atoi(args[1]);
        } else if (strcmp(args[0], "InvitationFlag") == 0) {
            if (is_input_valid(WIFIDIRECT_INVITATIONFLAG, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            invitation_flag = (t_u8) atoi(args[1]);
        } else if (strcmp(args[0], "CountryString") == 0) {
            if (is_input_valid(WIFIDIRECT_COUNTRY, arg_num - 1, args + 1) !=
                SUCCESS) {
                goto done;
            }
            strncpy(country, args[1] + 1, 3);
            country[strlen(args[1]) - 2] = '\0';
        } else if (strncmp(args[0], "Regulatory_Class_", 17) == 0) {
            if (is_input_valid
                (WIFIDIRECT_REGULATORYCLASS, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            if (!no_of_chan_entries) {
                chan_entry_list = (t_u8 *) malloc(MAX_BUFFER_SIZE);
                if (!chan_entry_list) {
                    printf("ERR:cannot allocate memory for chan_entry_list!\n");
                    goto done;
                }
                memset(chan_entry_list, 0, MAX_BUFFER_SIZE);
                chan_buf = chan_entry_list;
            }
            no_of_chan_entries++;
            chan_entry_regulatory_class = (t_u8) atoi(args[1]);
        } else if (strncmp(args[0], "NumofChannels", 13) == 0) {
            if (is_input_valid(WIFIDIRECT_NO_OF_CHANNELS, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            chan_entry_num_of_channels = (t_u8) atoi(args[1]);
        } else if (strncmp(args[0], "ChanList", 8) == 0) {
            if (chan_entry_num_of_channels != (arg_num - 1)) {
                printf
                    ("ERR:no of channels in ChanList and NumofChannels do not match!\n");
                goto done;
            }
            if (is_input_valid(SCANCHANNELS, arg_num - 1, args + 1) != SUCCESS) {
                goto done;
            }
            for (i = 0; i < chan_entry_num_of_channels; i++)
                dev_channels[i] = (t_u8) atoi(args[i + 1]);
            total_chan_len += chan_entry_num_of_channels;
            memcpy(chan_buf, &chan_entry_regulatory_class, sizeof(t_u8));
            memcpy(chan_buf + 1, &chan_entry_num_of_channels, sizeof(t_u8));
            memcpy(chan_buf + 2, dev_channels, chan_entry_num_of_channels);
            chan_buf +=
                sizeof(t_u8) + sizeof(t_u8) + chan_entry_num_of_channels;
        } else if (strcmp(args[0], "NoA_Index") == 0) {
            if (is_input_valid(WIFIDIRECT_NOA_INDEX, arg_num - 1, args + 1) !=
                SUCCESS) {
                goto done;
            }
            noa_index = (t_u8) atoi(args[1]);
        } else if (strcmp(args[0], "OppPS") == 0) {
            if (is_input_valid(WIFIDIRECT_OPP_PS, arg_num - 1, args + 1) !=
                SUCCESS) {
                goto done;
            }
            opp_ps = (t_u8) atoi(args[1]);
        } else if (strcmp(args[0], "CTWindow") == 0) {
            if (is_input_valid(WIFIDIRECT_CTWINDOW, arg_num - 1, args + 1) !=
                SUCCESS) {
                goto done;
            }
            if ((opp_ps != 0) && (atoi(args[1]) < 10)) {
                printf
                    ("ERR: CTwindow should be greater than or equal to 10 if opp_ps is set!\n");
                goto done;
            }
            ctwindow_opp_ps = (t_u8) atoi(args[1]) | SET_OPP_PS(opp_ps);
        } else if (strncmp(args[0], "CountType", 9) == 0) {
            if (is_input_valid(WIFIDIRECT_COUNT_TYPE, arg_num - 1, args + 1) !=
                SUCCESS) {
                goto done;
            }
            no_of_noa++;
            if (no_of_noa > MAX_NOA_DESCRIPTORS) {
                printf("Number of descriptors should not be greater than %d\n",
                       MAX_NOA_DESCRIPTORS);
                goto done;
            }
            count_type = (t_u8) atoi(args[1]);
            noa_descriptor_list[no_of_noa - 1].count_type = count_type;
        } else if (strncmp(args[0], "Duration", 8) == 0) {
            if (is_input_valid(WIFIDIRECT_DURATION, arg_num - 1, args + 1) !=
                SUCCESS) {
                goto done;
            }
            duration = (t_u32) atoi(args[1]);
            duration = cpu_to_le32(duration);
            noa_descriptor_list[no_of_noa - 1].duration = duration;
        } else if (strncmp(args[0], "Interval", 8) == 0) {
            if (is_input_valid(WIFIDIRECT_INTERVAL, arg_num - 1, args + 1) !=
                SUCCESS) {
                goto done;
            }
            interval = (t_u32) atoi(args[1]);
            interval = cpu_to_le32(interval);
            noa_descriptor_list[no_of_noa - 1].interval = interval;
        } else if (strncmp(args[0], "StartTime", 9) == 0) {
            if (is_input_valid(WIFIDIRECT_START_TIME, arg_num - 1, args + 1) !=
                SUCCESS) {
                goto done;
            }
            start_time = (t_u32) atoi(args[1]);
            start_time = cpu_to_le32(start_time);
            noa_descriptor_list[no_of_noa - 1].start_time = start_time;
        } else if (strcmp(args[0], "PrimaryDeviceTypeCategory") == 0) {
            if (is_input_valid
                (WIFIDIRECT_PRIDEVTYPECATEGORY, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            pri_category = (t_u16) atoi(args[1]);
        } else if (strcmp(args[0], "PrimaryDeviceTypeOUI") == 0) {
            if (is_input_valid(WIFIDIRECT_PRIDEVTYPEOUI, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            for (i = 0; i < 4; i++)
                primary_oui[i] = (t_u8) A2HEXDECIMAL(args[i + 1]);
        } else if (strcmp(args[0], "PrimaryDeviceTypeSubCategory") == 0) {
            if (is_input_valid
                (WIFIDIRECT_PRIDEVTYPESUBCATEGORY, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            pri_sub_category = (t_u16) atoi(args[1]);
        } else if (strcmp(args[0], "SecondaryDeviceCount") == 0) {
            if (is_input_valid
                (WIFIDIRECT_SECONDARYDEVCOUNT, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            secondary_dev_count = (t_u8) atoi(args[1]);
            if (secondary_dev_count)
                memset(secondary_dev_info, 0, sizeof(secondary_dev_info));
        } else if (strncmp(args[0], "SecondaryDeviceTypeCategory", 27) == 0) {
            if (is_input_valid
                (WIFIDIRECT_PRIDEVTYPECATEGORY, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            sec_category = (t_u16) atoi(args[1]);
            sec_category = htons(sec_category);
            secondary_index++;
        } else if (strncmp(args[0], "SecondaryDeviceTypeOUI", 22) == 0) {
            if (is_input_valid(WIFIDIRECT_PRIDEVTYPEOUI, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            for (i = 0; i < 4; i++)
                secondary_oui[i] = (t_u8) A2HEXDECIMAL(args[i + 1]);
        } else if (strncmp(args[0], "SecondaryDeviceTypeSubCategory", 30) == 0) {
            if (is_input_valid
                (WIFIDIRECT_PRIDEVTYPESUBCATEGORY, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            if (secondary_index < 0 ||
                secondary_index >= MAX_SECONDARY_DEVICE_COUNT) {
                printf("Error in configuration file %s:%d", file_name, li);
                goto done;
            }
            sec_sub_category = (t_u16) atoi(args[1]);
            sec_sub_category = htons(sec_sub_category);
            if (secondary_dev_count) {
                memcpy(&secondary_dev_info
                       [secondary_index * WPS_DEVICE_TYPE_LEN], &sec_category,
                       sizeof(t_u16));
                memcpy(&secondary_dev_info
                       [(secondary_index * WPS_DEVICE_TYPE_LEN) + 2],
                       secondary_oui, sizeof(secondary_oui));
                memcpy(&secondary_dev_info
                       [(secondary_index * WPS_DEVICE_TYPE_LEN) + 6],
                       &sec_sub_category, sizeof(t_u16));
            }
        } else if (strcmp(args[0], "InterfaceAddressCount") == 0) {
            if (is_input_valid(WIFIDIRECT_INTERFACECOUNT, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            iface_count = (t_u8) atoi(args[1]);
        } else if (strcmp(args[0], "InterfaceAddressList") == 0) {
            if (iface_count != (arg_num - 1)) {
                printf("Incorrect address list for %d entries.\n", iface_count);
                goto done;
            }
            for (i = 0; i < iface_count && i < MAX_INTERFACE_ADDR_COUNT; i++) {
                if ((ret =
                     mac2raw(args[i + 1],
                             &iface_list[i * ETH_ALEN])) != SUCCESS) {
                    printf("ERR: %s Address \n",
                           ret == FAILURE ? "Invalid MAC" : ret ==
                           WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" :
                           "Multicast");
                    goto done;
                }
            }
        } else if (strcmp(args[0], "GroupConfigurationTimeout") == 0) {
            if (is_input_valid
                (WIFIDIRECT_ATTR_CONFIG_TIMEOUT, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            go_config_timeout = (t_u8) atoi(args[1]);
        } else if (strcmp(args[0], "ClientConfigurationTimeout") == 0) {
            if (is_input_valid
                (WIFIDIRECT_ATTR_CONFIG_TIMEOUT, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            client_config_timeout = (t_u8) atoi(args[1]);
        } else if (strcmp(args[0], "AvailabilityPeriod") == 0) {
            if (is_input_valid
                (WIFIDIRECT_ATTR_EXTENDED_TIME, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            avail_period = (t_u16) atoi(args[1]);
        } else if (strcmp(args[0], "AvailabilityInterval") == 0) {
            if (is_input_valid
                (WIFIDIRECT_ATTR_EXTENDED_TIME, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            avail_interval = (t_u16) atoi(args[1]);
        } else if (strcmp(args[0], "WPSConfigMethods") == 0) {
            if (is_input_valid(WIFIDIRECT_WPSCONFMETHODS, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            config_methods = (t_u16) A2HEXDECIMAL(args[1]);
        } else if (strcmp(args[0], "DeviceName") == 0 ||
                   strcmp(args[0], "GroupSsId") == 0) {
            memset(wifidirect_ssid, 0, sizeof(wifidirect_ssid));
            strncpy(wifidirect_ssid, args[1], sizeof(wifidirect_ssid) - 1);
        } else if (strcmp(args[0], "WPSVersion") == 0) {
            if (is_input_valid(WIFIDIRECT_WPSVERSION, arg_num - 1, args + 1) !=
                SUCCESS) {
                goto done;
            }
            WPS_version = (t_u8) A2HEXDECIMAL(args[1]);
        } else if (strcmp(args[0], "WPSSetupState") == 0) {
            if (is_input_valid(WIFIDIRECT_WPSSETUPSTATE, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            WPS_setupstate = (t_u8) A2HEXDECIMAL(args[1]);
        } else if (strcmp(args[0], "WPSDeviceName") == 0) {
            if (is_input_valid(WIFIDIRECT_WPSDEVICENAME, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            memset(WPS_devicename, 0, sizeof(WPS_devicename));
            strncpy(WPS_devicename, args[1], sizeof(WPS_devicename));
        } else if (strcmp(args[0], "WPSRequestType") == 0) {
            if (is_input_valid(WIFIDIRECT_WPSREQRESPTYPE, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            WPS_requesttype = (t_u8) A2HEXDECIMAL(args[1]);
        } else if (strcmp(args[0], "WPSResponseType") == 0) {
            if (is_input_valid(WIFIDIRECT_WPSREQRESPTYPE, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            WPS_responsetype = (t_u8) A2HEXDECIMAL(args[1]);
        } else if (strcmp(args[0], "WPSSpecConfigMethods") == 0) {
            if (is_input_valid
                (WIFIDIRECT_WPSSPECCONFMETHODS, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            WPS_specconfigmethods = (t_u16) A2HEXDECIMAL(args[1]);
        } else if (strcmp(args[0], "WPSUUID") == 0) {
            if (is_input_valid(WIFIDIRECT_WPSUUID, arg_num - 1, args + 1) !=
                SUCCESS) {
                goto done;
            }
            for (i = 0; i < WPS_UUID_MAX_LEN; i++)
                WPS_UUID[i] = (t_u8) A2HEXDECIMAL(args[i + 1]);
        } else if (strcmp(args[0], "WPSPrimaryDeviceType") == 0) {
            if (is_input_valid
                (WIFIDIRECT_WPSPRIMARYDEVICETYPE, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            for (i = 0; i < WPS_DEVICE_TYPE_MAX_LEN; i++)
                WPS_primarydevicetype[i] = (t_u8) A2HEXDECIMAL(args[i + 1]);
        } else if (strcmp(args[0], "WPSRFBand") == 0) {
            if (is_input_valid(WIFIDIRECT_WPSRFBAND, arg_num - 1, args + 1) !=
                SUCCESS) {
                goto done;
            }
            WPS_RFband = (t_u8) A2HEXDECIMAL(args[1]);
        } else if (strcmp(args[0], "WPSAssociationState") == 0) {
            if (is_input_valid
                (WIFIDIRECT_WPSASSOCIATIONSTATE, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            WPS_associationstate = (t_u16) A2HEXDECIMAL(args[1]);
        } else if (strcmp(args[0], "WPSConfigurationError") == 0) {
            if (is_input_valid
                (WIFIDIRECT_WPSCONFIGURATIONERROR, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            WPS_configurationerror = (t_u16) A2HEXDECIMAL(args[1]);
        } else if (strcmp(args[0], "WPSDevicePassword") == 0) {
            if (is_input_valid
                (WIFIDIRECT_WPSDEVICEPASSWORD, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            WPS_devicepassword = (t_u16) A2HEXDECIMAL(args[1]);
        } else if (strcmp(args[0], "WPSManufacturer") == 0) {
            if (is_input_valid
                (WIFIDIRECT_WPSMANUFACTURER, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            memset(WPS_manufacturer, 0, sizeof(WPS_manufacturer));
            strncpy(WPS_manufacturer, args[1], sizeof(WPS_manufacturer));
        } else if (strcmp(args[0], "WPSModelName") == 0) {
            if (is_input_valid(WIFIDIRECT_WPSMODELNAME, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            memset(WPS_modelname, 0, sizeof(WPS_modelname));
            strncpy(WPS_modelname, args[1], sizeof(WPS_modelname));
        } else if (strcmp(args[0], "WPSModelNumber") == 0) {
            if (is_input_valid(WIFIDIRECT_WPSMODELNUMBER, arg_num - 1, args + 1)
                != SUCCESS) {
                goto done;
            }
            for (i = 0; i < arg_num - 1; i++)
                WPS_modelnumber[i] = (t_u8) A2HEXDECIMAL(args[i + 1]);
            wps_model_len = arg_num - 1;
        } else if (strcmp(args[0], "WPSSerialNumber") == 0) {
            if (is_input_valid
                (WIFIDIRECT_WPSSERIALNUMBER, arg_num - 1,
                 args + 1) != SUCCESS) {
                goto done;
            }
            for (i = 0; i < arg_num - 1; i++)
                WPS_serialnumber[i] = (t_u8) A2HEXDECIMAL(args[i + 1]);
            wps_serial_len = arg_num - 1;
        } else if (strcmp(args[0], "Buffer") == 0) {
            for (i = 0; i < arg_num - 1; i++)
                extra[i] = (t_u8) A2HEXDECIMAL(args[i + 1]);
            extra_len = arg_num - 1;
        } else if (strcmp(args[0], "}") == 0) {
            /* Based on level, populate appropriate struct */
            switch (wifidirect_level) {
            case WIFIDIRECT_DEVICE_ID_CONFIG:
                {
                    tlvbuf_wifidirect_device_id *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len = sizeof(tlvbuf_wifidirect_device_id);
                    tlv =
                        (tlvbuf_wifidirect_device_id *) (buffer +
                                                         cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_DEVICE_ID;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    memcpy(tlv->dev_mac_address, dev_address, ETH_ALEN);
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    break;
                }
            case WIFIDIRECT_CAPABILITY_CONFIG:
                {
                    tlvbuf_wifidirect_capability *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len = sizeof(tlvbuf_wifidirect_capability);
                    tlv =
                        (tlvbuf_wifidirect_capability *) (buffer +
                                                          cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_CAPABILITY;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    tlv->dev_capability = dev_capability;
                    tlv->group_capability = group_capability;
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    break;
                }
            case WIFIDIRECT_GROUP_OWNER_INTENT_CONFIG:
                {
                    tlvbuf_wifidirect_group_owner_intent *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len = sizeof(tlvbuf_wifidirect_group_owner_intent);
                    tlv =
                        (tlvbuf_wifidirect_group_owner_intent *) (buffer +
                                                                  cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_GROUPOWNER_INTENT;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    tlv->dev_intent = group_owner_intent;
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    break;
                }
            case WIFIDIRECT_MANAGEABILITY_CONFIG:
                {
                    tlvbuf_wifidirect_manageability *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len = sizeof(tlvbuf_wifidirect_manageability);
                    tlv =
                        (tlvbuf_wifidirect_manageability *) (buffer +
                                                             cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_MANAGEABILITY;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    tlv->manageability = manageability;
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    break;
                }
            case WIFIDIRECT_INVITATION_FLAG_CONFIG:
                {
                    tlvbuf_wifidirect_invitation_flag *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len = sizeof(tlvbuf_wifidirect_invitation_flag);
                    tlv =
                        (tlvbuf_wifidirect_invitation_flag *) (buffer +
                                                               cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_INVITATION_FLAG;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    tlv->invitation_flag |= invitation_flag;
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    break;
                }
            case WIFIDIRECT_CHANNEL_LIST_CONFIG:
                {
                    tlvbuf_wifidirect_channel_list *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len = sizeof(tlvbuf_wifidirect_channel_list)
                        + no_of_chan_entries * sizeof(chan_entry) +
                        total_chan_len;
                    tlv =
                        (tlvbuf_wifidirect_channel_list *) (buffer +
                                                            cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_CHANNEL_LIST;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    memcpy(tlv->country_string, country, 3);
                    if (tlv->country_string[2] == 0)
                        tlv->country_string[2] = WIFIDIRECT_COUNTRY_LAST_BYTE;
                    memcpy(tlv->wifidirect_chan_entry_list, chan_entry_list,
                           (tlv->length - 3));
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    break;
                }
            case WIFIDIRECT_NOTICE_OF_ABSENCE:
                {
                    tlvbuf_wifidirect_notice_of_absence *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len = sizeof(tlvbuf_wifidirect_notice_of_absence)
                        + no_of_noa * sizeof(noa_descriptor);
                    tlv =
                        (tlvbuf_wifidirect_notice_of_absence *) (buffer +
                                                                 cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_NOTICE_OF_ABSENCE;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    tlv->noa_index = noa_index;
                    tlv->ctwindow_opp_ps = ctwindow_opp_ps;
                    memcpy(tlv->wifidirect_noa_descriptor_list,
                           noa_descriptor_list,
                           no_of_noa * sizeof(noa_descriptor));
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    flag = 1;
                    break;
                }
            case WIFIDIRECT_NOA_DESCRIPTOR:
                {
                    wifidirect_level = WIFIDIRECT_NOTICE_OF_ABSENCE;
                    flag = 0;
                    break;
                }
            case WIFIDIRECT_CHANNEL_CONFIG:
                {
                    tlvbuf_wifidirect_channel *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len = sizeof(tlvbuf_wifidirect_channel);
                    tlv =
                        (tlvbuf_wifidirect_channel *) (buffer +
                                                       cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_CHANNEL;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    memcpy(tlv->country_string, country, 3);
                    if (tlv->country_string[2] == 0)
                        tlv->country_string[2] = WIFIDIRECT_COUNTRY_LAST_BYTE;
                    tlv->regulatory_class = regulatory_class;
                    tlv->channel_number = channel_number;
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    break;
                }
            case WIFIDIRECT_OPCHANNEL_CONFIG:
                {
                    tlvbuf_wifidirect_channel *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len = sizeof(tlvbuf_wifidirect_channel);
                    tlv =
                        (tlvbuf_wifidirect_channel *) (buffer +
                                                       cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_OPCHANNEL;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    memcpy(tlv->country_string, country, 3);
                    if (tlv->country_string[2] == 0)
                        tlv->country_string[2] = WIFIDIRECT_COUNTRY_LAST_BYTE;
                    tlv->regulatory_class = op_regulatory_class;
                    tlv->channel_number = op_channel_number;
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    break;
                }

            case WIFIDIRECT_DEVICE_INFO_CONFIG:
                {
                    tlvbuf_wifidirect_device_info *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len = sizeof(tlvbuf_wifidirect_device_info) +
                        secondary_dev_count * WPS_DEVICE_TYPE_LEN +
                        strlen(wifidirect_ssid);
                    tlv =
                        (tlvbuf_wifidirect_device_info *) (buffer +
                                                           cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_DEVICE_INFO;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    memcpy(tlv->dev_address, dev_address, ETH_ALEN);
                    tlv->config_methods = htons(config_methods);
                    tlv->primary_category = htons(pri_category);
                    memcpy(tlv->primary_oui, primary_oui, 4);
                    tlv->primary_subcategory = htons(pri_sub_category);
                    tlv->secondary_dev_count = secondary_dev_count;
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    /* Parameters within secondary_dev_info are already
                       htons'ed */
                    memcpy(tlv->secondary_dev_info, secondary_dev_info,
                           secondary_dev_count * WPS_DEVICE_TYPE_LEN);
                    temp = htons(SC_Device_Name);
                    memcpy(((t_u8 *) (&tlv->device_name_type)) +
                           secondary_dev_count * WPS_DEVICE_TYPE_LEN, &temp,
                           sizeof(temp));
                    temp = htons(strlen(wifidirect_ssid));
                    memcpy(((t_u8 *) (&tlv->device_name_len)) +
                           secondary_dev_count * WPS_DEVICE_TYPE_LEN, &temp,
                           sizeof(temp));
                    memcpy(((t_u8 *) (&tlv->device_name)) +
                           secondary_dev_count * WPS_DEVICE_TYPE_LEN,
                           wifidirect_ssid, strlen(wifidirect_ssid));
                    flag = 1;
                    break;
                }
            case WIFIDIRECT_GROUP_INFO_CONFIG:
                {
                    tlvbuf_wifidirect_group_info *tlv = NULL;
                    /* Append a new TLV */
                    tlv_offset = wifidirect_group_total_ssid_len
                        +
                        wifidirect_total_secondary_dev_count *
                        WPS_DEVICE_TYPE_LEN;
                    tlv_len = sizeof(tlvbuf_wifidirect_group_info)
                        +
                        wifidirect_client_dev_count *
                        sizeof(wifidirect_client_dev_info) + tlv_offset;
                    tlv =
                        (tlvbuf_wifidirect_group_info *) (buffer +
                                                          cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_GROUP_INFO;
                    tlv->length = tlv_len;
                    memcpy(tlv->wifidirect_client_dev_list,
                           wifidirect_client_dev_info_list,
                           wifidirect_client_dev_count *
                           sizeof(wifidirect_client_dev_info) + tlv_offset);
                    /* Parameters within secondary_dev_info are already
                       htons'ed */
                    // wps_hexdump(DEBUG_WLAN,"Group Info Hexdump:",
                    // (t_u8*)tlv, tlv_len);
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    flag = 1;
                    break;
                }
            case WIFIDIRECT_GROUP_SEC_INFO_CONFIG:
                {
                    wifidirect_level = WIFIDIRECT_GROUP_CLIENT_INFO_CONFIG;

                    if (wifidirect_client_dev_index && group_secondary_index) {
                        memset(((t_u8 *) &
                                wifidirect_client_dev_info_list
                                [wifidirect_client_dev_index -
                                 1].wifidirect_secondary_dev_info + tlv_offset),
                               0, group_secondary_index * WPS_DEVICE_TYPE_LEN);
                        memcpy(((t_u8 *) &
                                wifidirect_client_dev_info_list
                                [wifidirect_client_dev_index -
                                 1].wifidirect_secondary_dev_info + tlv_offset),
                               &group_secondary_dev_info,
                               group_secondary_index * WPS_DEVICE_TYPE_LEN);
                    }
                    tlv_offset = wifidirect_group_total_ssid_len
                        +
                        wifidirect_total_secondary_dev_count *
                        WPS_DEVICE_TYPE_LEN;
                    flag = 0;
                    break;
                }
            case WIFIDIRECT_GROUP_CLIENT_INFO_CONFIG:
                {
                    wifidirect_level = WIFIDIRECT_GROUP_INFO_CONFIG;
                    flag = 0;
                    break;
                }
            case WIFIDIRECT_DEVICE_SEC_INFO_CONFIG:
                {
                    wifidirect_level = WIFIDIRECT_DEVICE_INFO_CONFIG;
                    flag = 0;
                    break;
                }
            case WIFIDIRECT_GROUP_ID_CONFIG:
                {
                    tlvbuf_wifidirect_group_id *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len =
                        sizeof(tlvbuf_wifidirect_group_id) +
                        strlen(wifidirect_ssid);
                    tlv =
                        (tlvbuf_wifidirect_group_id *) (buffer +
                                                        cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_GROUP_ID;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    memcpy(tlv->group_address, dev_address, ETH_ALEN);
                    memcpy(tlv->group_ssid, wifidirect_ssid,
                           strlen(wifidirect_ssid));
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    break;
                }
            case WIFIDIRECT_GROUP_BSS_ID_CONFIG:
                {
                    tlvbuf_wifidirect_group_bss_id *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len = sizeof(tlvbuf_wifidirect_group_bss_id);
                    tlv =
                        (tlvbuf_wifidirect_group_bss_id *) (buffer +
                                                            cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_GROUP_BSS_ID;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    memcpy(tlv->group_bssid, dev_address, ETH_ALEN);
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    break;
                }
            case WIFIDIRECT_INTERFACE_CONFIG:
                {
                    tlvbuf_wifidirect_interface *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len = sizeof(tlvbuf_wifidirect_interface)
                        + iface_count * ETH_ALEN;
                    tlv =
                        (tlvbuf_wifidirect_interface *) (buffer +
                                                         cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_INTERFACE;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    memcpy(tlv->interface_id, dev_address, ETH_ALEN);
                    tlv->interface_count = iface_count;
                    memcpy(tlv->interface_idlist, iface_list,
                           iface_count * ETH_ALEN);
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    break;
                }

            case WIFIDIRECT_TIMEOUT_CONFIG:
                {
                    tlvbuf_wifidirect_config_timeout *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len = sizeof(tlvbuf_wifidirect_config_timeout);
                    tlv =
                        (tlvbuf_wifidirect_config_timeout *) (buffer +
                                                              cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_CONFIG_TIMEOUT;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    tlv->group_config_timeout = go_config_timeout;
                    tlv->device_config_timeout = client_config_timeout;
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    break;
                }
            case WIFIDIRECT_EXTENDED_TIME_CONFIG:
                {
                    tlvbuf_wifidirect_ext_listen_time *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len = sizeof(tlvbuf_wifidirect_ext_listen_time);
                    tlv =
                        (tlvbuf_wifidirect_ext_listen_time *) (buffer +
                                                               cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_EXTENDED_LISTEN_TIME;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    tlv->availability_period = le16_to_cpu(avail_period);
                    tlv->availability_interval = le16_to_cpu(avail_interval);
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    break;
                }
            case WIFIDIRECT_INTENDED_ADDR_CONFIG:
                {
                    tlvbuf_wifidirect_intended_addr *tlv = NULL;
                    /* Append a new TLV */
                    tlv_len = sizeof(tlvbuf_wifidirect_intended_addr);
                    tlv =
                        (tlvbuf_wifidirect_intended_addr *) (buffer +
                                                             cmd_len_wifidirect);
                    cmd_len_wifidirect += tlv_len;
                    /* Set TLV fields */
                    tlv->tag = TLV_TYPE_WIFIDIRECT_INTENDED_ADDRESS;
                    tlv->length = tlv_len - (sizeof(t_u8) + sizeof(t_u16));
                    memcpy(tlv->group_address, dev_address, ETH_ALEN);
                    endian_convert_tlv_wifidirect_header_out(tlv);
                    break;
                }

            case WIFIDIRECT_WPSIE:
                {
#ifdef DEBUG
                    /* Debug print */
                    hexdump(buffer, cmd_len_wifidirect, ' ');
#endif
                    /* Append TLV for WPSVersion */
                    tlvbuf_wps_ie *tlv = NULL;
                    tlv_len = sizeof(tlvbuf_wps_ie) + sizeof(WPS_version);
                    tlv = (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                             sizeof(custom_ie) + cmd_len_wps);

                    if (!wifidir_use_fixed_ie_indices()) {
                        special_mask_custom_ie_buf *wps_ie_buf;
                        wps_ie_buf = (special_mask_custom_ie_buf *) tlv;
                        memcpy(&wps_ie_buf->Oui[0], wps_oui, sizeof(wps_oui));
                        cmd_len_wps += sizeof(wps_oui);
                    }
                    tlv = (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                             sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_Version;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    *(tlv->data) = WPS_version;
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;

                    /* Append TLV for WPSSetupState */
                    tlv_len = sizeof(tlvbuf_wps_ie) + sizeof(WPS_setupstate);
                    tlv = (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                             sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_Simple_Config_State;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    *(tlv->data) = WPS_setupstate;
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;

                    /* Append TLV for WPSRequestType */
                    tlv_len = sizeof(tlvbuf_wps_ie) + sizeof(WPS_requesttype);
                    tlv = (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                             sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_Request_Type;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    *(tlv->data) = WPS_requesttype;
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;

                    /* Append TLV for WPSResponseType */
                    tlv_len = sizeof(tlvbuf_wps_ie) + sizeof(WPS_responsetype);
                    tlv = (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                             sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_Response_Type;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    *(tlv->data) = WPS_responsetype;
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;

                    /* Append TLV for WPSSpecConfigMethods */
                    tlv_len =
                        sizeof(tlvbuf_wps_ie) + sizeof(WPS_specconfigmethods);
                    tlv =
                        (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                           sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_Config_Methods;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    temp = htons(WPS_specconfigmethods);
                    memcpy((t_u16 *) tlv->data, &temp, sizeof(temp));
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;

                    /* Append TLV for WPSUUID */
                    tlv_len = sizeof(tlvbuf_wps_ie) + sizeof(WPS_UUID);
                    tlv = (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                             sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_UUID_E;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    memcpy(tlv->data, WPS_UUID, WPS_UUID_MAX_LEN);
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;

                    /* Append TLV for WPSPrimaryDeviceType */
                    tlv_len =
                        sizeof(tlvbuf_wps_ie) + sizeof(WPS_primarydevicetype);
                    tlv =
                        (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                           sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_Primary_Device_Type;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    memcpy(tlv->data, WPS_primarydevicetype,
                           WPS_DEVICE_TYPE_MAX_LEN);
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;

                    /* Append TLV for WPSRFBand */
                    tlv_len = sizeof(tlvbuf_wps_ie) + sizeof(WPS_RFband);
                    tlv = (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                             sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_RF_Band;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    *(tlv->data) = WPS_RFband;
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;

                    /* Append TLV for WPSAssociationState */
                    tlv_len =
                        sizeof(tlvbuf_wps_ie) + sizeof(WPS_associationstate);
                    tlv =
                        (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                           sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_Association_State;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    temp = htons(WPS_associationstate);
                    memcpy((t_u16 *) tlv->data, &temp, sizeof(temp));
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;

                    /* Append TLV for WPSConfigurationError */
                    tlv_len =
                        sizeof(tlvbuf_wps_ie) + sizeof(WPS_configurationerror);
                    tlv =
                        (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                           sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_Configuration_Error;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    temp = htons(WPS_configurationerror);
                    memcpy((t_u16 *) tlv->data, &temp, sizeof(temp));
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;

                    /* Append TLV for WPSDevicePassword */
                    tlv_len =
                        sizeof(tlvbuf_wps_ie) + sizeof(WPS_devicepassword);
                    tlv =
                        (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                           sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_Device_Password_ID;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    temp = htons(WPS_devicepassword);
                    memcpy((t_u16 *) tlv->data, &temp, sizeof(temp));
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;

                    /* Append TLV for WPSDeviceName */
                    tlv_len = sizeof(tlvbuf_wps_ie) + strlen(WPS_devicename);
                    tlv = (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                             sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_Device_Name;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    memcpy(tlv->data, WPS_devicename, strlen(WPS_devicename));
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;

                    /* Append TLV for WPSManufacturer */
                    tlv_len = sizeof(tlvbuf_wps_ie) + strlen(WPS_manufacturer);
                    tlv = (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                             sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_Manufacturer;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    memcpy(tlv->data, WPS_manufacturer,
                           strlen(WPS_manufacturer));
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;

                    /* Append TLV for WPSModelName */
                    tlv_len = sizeof(tlvbuf_wps_ie) + strlen(WPS_modelname);
                    tlv = (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                             sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_Model_Name;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    memcpy(tlv->data, WPS_modelname, strlen(WPS_modelname));
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;

                    /* Append TLV for WPSModelNumber */
                    tlv_len = sizeof(tlvbuf_wps_ie) + wps_model_len;
                    tlv = (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                             sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_Model_Number;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    memcpy(tlv->data, WPS_modelnumber, wps_model_len);
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;

                    /* Append TLV for WPSSerialNumber */
                    tlv_len = sizeof(tlvbuf_wps_ie) + wps_serial_len;
                    tlv = (tlvbuf_wps_ie *) (buffer + cmd_len_wifidirect +
                                             sizeof(custom_ie) + cmd_len_wps);
                    tlv->tag = SC_Serial_Number;
                    tlv->length = tlv_len - 2 * sizeof(t_u16);
                    memcpy(tlv->data, WPS_serialnumber, wps_serial_len);
                    endian_convert_tlv_wps_header_out(tlv);
                    cmd_len_wps += tlv_len;
#ifdef DEBUG
                    /* Debug print */
                    hexdump(buffer + sizeof(custom_ie) + cmd_len_wifidirect,
                            cmd_len_wps, ' ');
#endif
                    break;
                }
            case WIFIDIRECT_EXTRA:
                {
                    memcpy(buffer + cmd_len_wifidirect, extra, extra_len);
                    cmd_len_wifidirect += extra_len;
                    break;
                }
            default:
                *ie_len_wifidirect = cmd_len_wifidirect;
                if (ie_len_wps)
                    *ie_len_wps = cmd_len_wps;
                break;
            }
            memset(country, 0, sizeof(country));
            if (wifidirect_level == 0)
                cmd_found = 0;
            if (flag)
                wifidirect_level = 0;
        }
    }

  done:
    fclose(config_file);
    if (chan_entry_list)
        free(chan_entry_list);
    if (line)
        free(line);
    if (extra)
        free(extra);
    if (args)
        free(args);
    return;
}

/** 
 *  @brief Process and send ie config command 
 *  @param ie_index  A pointer to the IE buffer index
 *  @param data_len_wifidirect  Length of WIFIDIRECT data, 0 to get, else set.
 *  @param data_len_wps  Length of WPS data, 0 to get, else set.
 *  @param buf      Pointer to buffer to set.
 *  @return          SUCCESS--success, FAILURE--fail
 */
static int
wifidirect_ie_config(t_u16 * ie_index, t_u16 data_len_wifidirect,
                     t_u16 data_len_wps, t_u8 * buf)
{
    struct iwreq iwr;
    t_s32 sockfd;
    int i, ret = SUCCESS;
    tlvbuf_custom_ie *tlv = NULL;
    custom_ie *ie_ptr = NULL;

    tlv = (tlvbuf_custom_ie *) buf;
    tlv->tag = MRVL_MGMT_IE_LIST_TLV_ID;
    /* Locate headers */
    ie_ptr = (custom_ie *) (tlv->ie_data);

    /* Set TLV fields : WIFIDIRECT IE parameters */
    if (data_len_wifidirect) {
        /* Set IE */
#define MGMT_MASK_AUTO	0xffff
        ie_ptr->mgmt_subtype_mask = MGMT_MASK_AUTO;
        tlv->length = sizeof(custom_ie) + data_len_wifidirect;
        ie_ptr->ie_length = data_len_wifidirect;
        ie_ptr->ie_index = *ie_index;
    } else {
        /* Get WPS IE */
        tlv->length = 0;
    }

    if (!wifidir_use_fixed_ie_indices()) {
        if (*ie_index != 0xFFFF) {
            (*ie_index)++;
        }
    } else {
        (*ie_index)++;
    }
    /* Locate headers */
    ie_ptr =
        (custom_ie *) ((t_u8 *) (tlv->ie_data) + sizeof(custom_ie) +
                       data_len_wifidirect);

    /* Set WPS IE parameters */
    if (data_len_wps) {
        /* Set IE */
        /* Firmware Handled IE - mask should be set to -1 */
        ie_ptr->mgmt_subtype_mask = MGMT_MASK_AUTO;
        tlv->length += sizeof(custom_ie) + data_len_wps;
        ie_ptr->ie_length = data_len_wps;
        ie_ptr->ie_index = *ie_index;
    }

    memset(&iwr, 0, sizeof(iwr));
    strncpy(iwr.ifr_name, (char *) dev_name, IFNAMSIZ - 1);

    iwr.u.data.pointer = (void *) buf;
    iwr.u.data.length = ((2 * sizeof(custom_ie)) + sizeof(tlvbuf_custom_ie) +
                         data_len_wifidirect + data_len_wps);
    iwr.u.data.flags = 0;

    /* 
     * create a socket 
     */
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        printf("Cannot open socket.\n");
        ret = FAILURE;
        goto _exit_;
    }

    if (ioctl(sockfd, CUSTOM_IE, &iwr)) {
        perror("ioctl[CUSTOM_IE]");
        printf("Failed to set/get/clear the IE buffer\n");
        ret = FAILURE;
        close(sockfd);
        goto _exit_;
    }
    close(sockfd);

/** Max IE index */
#define MAX_MGMT_IE_INDEX               12

    if (!data_len_wifidirect) {
        /* Get the IE buffer index number for MGMT_IE_LIST_TLV */
        tlv = (tlvbuf_custom_ie *) buf;
        *ie_index = 0xFFFF;
        if (tlv->tag == MRVL_MGMT_IE_LIST_TLV_ID) {
            ie_ptr = (custom_ie *) (tlv->ie_data);
            for (i = 0; i < MAX_MGMT_IE_INDEX; i++) {
                /* zero mask indicates a wps IE, return previous index */
                if (ie_ptr->mgmt_subtype_mask == MGMT_MASK_AUTO &&
                    ie_ptr->ie_length) {
                    *ie_index = ie_ptr->ie_index;
                    break;
                }
                if (i < (MAX_MGMT_IE_INDEX - 1))
                    ie_ptr =
                        (custom_ie *) ((t_u8 *) ie_ptr + sizeof(custom_ie) +
                                       ie_ptr->ie_length);
            }
        }
        if (*ie_index == 0xFFFF) {
            ret = FAILURE;
        }
    }
  _exit_:

    return ret;
}

/** 
 *  @brief Creates a wifidirect_config request and sends to the driver
 *
 *  Usage: "Usage : wifidirect_config [CONFIG_FILE]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         None 
 */
static void
wifidirectcmd_config(int argc, char *argv[])
{
    t_u8 *buf = NULL, *ptr, *dev_ptr, *array_ptr;
    t_u16 ie_len_wifidirect = 0, ie_len_wps = 0, ie_len;
    t_u16 ie_index, temp;
    int i, opt, ret = SUCCESS;
    tlvbuf_custom_ie *tlv = NULL;
    custom_ie *ie_ptr = NULL;
    t_u16 len = 0, len_wifidirect = 0;
    t_u8 type = 0;
    t_u16 wps_len = 0, wps_type = 0;

    if (!wifidir_use_fixed_ie_indices()) {
        ie_index = 0xFFFF;
    } else {
        ie_index = 0;
    }
    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_config_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if (argc < 2) {
        printf("ERR:wrong number of arguments.\n");
        print_wifidirect_config_usage();
        return;
    }
    buf = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);
    if (!buf) {
        printf("ERR:Cannot allocate memory!\n");
        return;
    }
    memset(buf, 0, MRVDRV_SIZE_OF_CMD_BUFFER);

    if (argc >= 3) {
        /* Read parameters and send command to firmware */
        wifidirect_file_params_config(argv[2], argv[1], buf
                                      + sizeof(tlvbuf_custom_ie) +
                                      sizeof(custom_ie), &ie_len_wifidirect,
                                      &ie_len_wps);
        if (argc == 4) {
            ie_index = atoi(argv[3]);
            if (ie_index >= 4) {
                printf("ERR:wrong argument %s.\n", argv[3]);
                return;
            }
        }
        if (ie_len_wifidirect > MAX_SIZE_IE_BUFFER ||
            ie_len_wps > MAX_SIZE_IE_BUFFER) {
            printf("ERR:IE parameter size exceeds limit in %s.\n", argv[2]);
            free(buf);
            return;
        }
        ie_len =
            ie_len_wifidirect + ie_len_wps + sizeof(tlvbuf_custom_ie) +
            (2 * sizeof(custom_ie));
        if (ie_len >= MRVDRV_SIZE_OF_CMD_BUFFER) {
            printf("ERR:Too much data in configuration file %s.\n", argv[2]);
            free(buf);
            return;
        }
#ifdef DEBUG
        hexdump(buf, ie_len, ' ');
#endif
        ret =
            wifidirect_ie_config(&ie_index, ie_len_wifidirect, ie_len_wps, buf);
        if (ret != SUCCESS) {
            printf("ERR:Could not set wifidirect parameters\n");
        }
    } else {
        ret = wifidirect_ie_config(&ie_index, 0, 0, buf);
        /* Print response */
        if (ret == SUCCESS && ie_index < 3) {
            tlv = (tlvbuf_custom_ie *) buf;
            if (tlv->tag == MRVL_MGMT_IE_LIST_TLV_ID) {
                ie_ptr = (custom_ie *) (tlv->ie_data);
                /* Goto appropriate Ie Index */
                for (i = 0; i < ie_index; i++) {
                    ie_ptr =
                        (custom_ie *) ((t_u8 *) ie_ptr + sizeof(custom_ie) +
                                       ie_ptr->ie_length);
                }
                ie_len_wifidirect = ie_ptr->ie_length;
                ptr = ie_ptr->ie_buffer;
                /* Locate headers */
                printf("WIFIDIRECT settings:\n");
                if (!wifidir_use_fixed_ie_indices()) {
                    while (memcmp(ptr, wifidirect_oui, sizeof(wifidirect_oui))) {
                        ie_ptr =
                            (custom_ie *) ((t_u8 *) ie_ptr + sizeof(custom_ie) +
                                           ie_ptr->ie_length);
                        ie_len_wifidirect = ie_ptr->ie_length;
                        ptr = ie_ptr->ie_buffer;
                    }
                    ptr += sizeof(wifidirect_oui);
                    ie_len_wifidirect -= sizeof(wifidirect_oui);
                }
                while (ie_len_wifidirect > WIFIDIRECT_IE_HEADER_LEN) {
                    type = *ptr;
                    memcpy(&len, ptr + 1, sizeof(t_u16));
                    len = le16_to_cpu(len);
                    switch (type) {
                    case TLV_TYPE_WIFIDIRECT_DEVICE_ID:
                        {
                            tlvbuf_wifidirect_device_id *wifidirect_tlv =
                                (tlvbuf_wifidirect_device_id *) ptr;
                            printf("\t Device ID - ");
                            print_mac(wifidirect_tlv->dev_mac_address);
                            printf("\n");
                        }
                        break;

                    case TLV_TYPE_WIFIDIRECT_CAPABILITY:
                        {
                            tlvbuf_wifidirect_capability *wifidirect_tlv =
                                (tlvbuf_wifidirect_capability *) ptr;
                            printf("\t Device capability = %d\n",
                                   (int) wifidirect_tlv->dev_capability);
                            printf("\t Group capability = %d\n",
                                   (int) wifidirect_tlv->group_capability);
                        }
                        break;
                    case TLV_TYPE_WIFIDIRECT_GROUPOWNER_INTENT:
                        {
                            tlvbuf_wifidirect_group_owner_intent *wifidirect_tlv
                                = (tlvbuf_wifidirect_group_owner_intent *) ptr;
                            printf("\t Group owner intent = %d\n",
                                   (int) wifidirect_tlv->dev_intent);
                        }
                        break;
                    case TLV_TYPE_WIFIDIRECT_MANAGEABILITY:
                        {
                            tlvbuf_wifidirect_manageability *wifidirect_tlv =
                                (tlvbuf_wifidirect_manageability *) ptr;
                            printf("\t Manageability = %d\n",
                                   (int) wifidirect_tlv->manageability);
                        }
                        break;
                    case TLV_TYPE_WIFIDIRECT_CHANNEL_LIST:
                        {
                            tlvbuf_wifidirect_channel_list *wifidirect_tlv =
                                (tlvbuf_wifidirect_channel_list *) ptr;
                            chan_entry *temp_ptr;
                            printf("\t Country String \"%c%c\"",
                                   wifidirect_tlv->country_string[0],
                                   wifidirect_tlv->country_string[1]);
                            if (isalpha(wifidirect_tlv->country_string[2]))
                                printf("\"%c\"",
                                       wifidirect_tlv->country_string[2]);
                            printf("\n");
                            temp_ptr =
                                (chan_entry *) wifidirect_tlv->
                                wifidirect_chan_entry_list;
                            len_wifidirect =
                                le16_to_cpu(wifidirect_tlv->length) -
                                (sizeof(tlvbuf_wifidirect_channel_list) -
                                 WIFIDIRECT_IE_HEADER_LEN);
                            if (len_wifidirect)
                                printf("\t Channel List :- \n");
                            while (len_wifidirect) {
                                printf("\t\t Regulatory_class = %d\n",
                                       (int) (temp_ptr->regulatory_class));
                                printf("\t\t No of channels = %d\n",
                                       (int) temp_ptr->num_of_channels);
                                printf("\t\t Channel list = ");
                                for (i = 0; i < temp_ptr->num_of_channels; i++) {
                                    printf("%d ", *(temp_ptr->chan_list + i));
                                }
                                len_wifidirect -=
                                    sizeof(chan_entry) +
                                    temp_ptr->num_of_channels;
                                temp_ptr =
                                    (chan_entry *) ((t_u8 *) temp_ptr +
                                                    sizeof(chan_entry) +
                                                    temp_ptr->num_of_channels);
                                printf("\n");
                            }
                        }
                        break;
                    case TLV_TYPE_WIFIDIRECT_NOTICE_OF_ABSENCE:
                        {
                            tlvbuf_wifidirect_notice_of_absence *wifidirect_tlv
                                = (tlvbuf_wifidirect_notice_of_absence *) ptr;
                            noa_descriptor *temp_ptr;
                            printf("\t Notice of Absence index = %d\n",
                                   (int) wifidirect_tlv->noa_index);
                            printf
                                ("\t CTWindow and opportunistic PS parameters = %d\n",
                                 (int) wifidirect_tlv->ctwindow_opp_ps);
                            temp_ptr =
                                (noa_descriptor *) wifidirect_tlv->
                                wifidirect_noa_descriptor_list;
                            len_wifidirect =
                                le16_to_cpu(wifidirect_tlv->length) -
                                (sizeof(tlvbuf_wifidirect_notice_of_absence) -
                                 WIFIDIRECT_IE_HEADER_LEN);
                            while (len_wifidirect) {
                                printf("\t Count or Type = %d\n",
                                       (int) temp_ptr->count_type);
                                printf("\t Duration = %dms\n",
                                       le32_to_cpu(temp_ptr->duration));
                                printf("\t Interval = %dms\n",
                                       le32_to_cpu(temp_ptr->interval));
                                printf("\t Start Time = %d\n",
                                       le32_to_cpu(temp_ptr->start_time));
                                printf("\n");
                                temp_ptr += sizeof(noa_descriptor);
                                len_wifidirect -= sizeof(noa_descriptor);
                            }
                        }
                        break;
                    case TLV_TYPE_WIFIDIRECT_DEVICE_INFO:
                        {
                            tlvbuf_wifidirect_device_info *wifidirect_tlv =
                                (tlvbuf_wifidirect_device_info *) ptr;
                            printf("\t Device address - ");
                            print_mac(wifidirect_tlv->dev_address);
                            printf("\n");
                            /* display config_methods */
                            printf("\t Config methods - 0x%02X\n",
                                   ntohs(wifidirect_tlv->config_methods));
                            printf
                                ("\t Primary device type = %02d-%02X%02X%02X%02X-%02d\n",
                                 (int) ntohs(wifidirect_tlv->primary_category),
                                 (int) wifidirect_tlv->primary_oui[0],
                                 (int) wifidirect_tlv->primary_oui[1],
                                 (int) wifidirect_tlv->primary_oui[2],
                                 (int) wifidirect_tlv->primary_oui[3],
                                 (int) ntohs(wifidirect_tlv->
                                             primary_subcategory));
                            printf("\t Secondary Device Count = %d\n",
                                   (int) wifidirect_tlv->secondary_dev_count);
                            array_ptr = wifidirect_tlv->secondary_dev_info;
                            for (i = 0; i < wifidirect_tlv->secondary_dev_count;
                                 i++) {
                                memcpy(&temp, array_ptr, sizeof(t_u16));
                                printf("\t\t Secondary device type = %02d-",
                                       ntohs(temp));
                                array_ptr += sizeof(temp);
                                printf("%02X%02X%02X%02X", array_ptr[0],
                                       array_ptr[1], array_ptr[2],
                                       array_ptr[3]);
                                array_ptr += 4;
                                memcpy(&temp, array_ptr, sizeof(t_u16));
                                printf("-%02d\n", ntohs(temp));
                                array_ptr += sizeof(temp);
                            }
                            array_ptr = wifidirect_tlv->device_name +
                                wifidirect_tlv->secondary_dev_count *
                                WPS_DEVICE_TYPE_LEN;
                            dev_ptr =
                                (((t_u8 *) (&wifidirect_tlv->device_name_len)) +
                                 wifidirect_tlv->secondary_dev_count *
                                 WPS_DEVICE_TYPE_LEN);
                            if (*(t_u16 *) dev_ptr)
                                printf("\t Device Name =  ");
                            memcpy(&temp, dev_ptr, sizeof(t_u16));
                            for (i = 0; i < ntohs(temp); i++)
                                printf("%c", *array_ptr++);
                            printf("\n");
                        }
                        break;
                    case TLV_TYPE_WIFIDIRECT_GROUP_INFO:
                        {
                            tlvbuf_wifidirect_group_info *wifidirect_tlv =
                                (tlvbuf_wifidirect_group_info *) ptr;
                            t_u8 no_of_wifidirect_clients =
                                0, wifidirect_client_dev_length = 0;
                            wifidirect_client_dev_info *temp_ptr;
                            temp_ptr =
                                (wifidirect_client_dev_info *) wifidirect_tlv->
                                wifidirect_client_dev_list;
                            if (temp_ptr == NULL)
                                break;
                            wifidirect_client_dev_length = temp_ptr->dev_length;
                            temp =
                                le16_to_cpu(wifidirect_tlv->length) -
                                wifidirect_client_dev_length;
                            while (temp) {

                                printf
                                    ("\t Group WifiDirect Client Device address - ");
                                print_mac(temp_ptr->wifidirect_dev_address);
                                printf("\n");
                                printf
                                    ("\t Group WifiDirect Client Interface address - ");
                                print_mac(temp_ptr->wifidirect_intf_address);
                                printf("\n");
                                printf
                                    ("\t Group WifiDirect Client Device capability = %d\n",
                                     (int) temp_ptr->wifidirect_dev_capability);
                                printf
                                    ("\t Group WifiDirect Client Config methods - 0x%02X\n",
                                     ntohs(temp_ptr->config_methods));
                                printf
                                    ("\t Group WifiDirect Client Primay device type = %02d-%02X%02X%02X%02X-%02d\n",
                                     (int) ntohs(temp_ptr->primary_category),
                                     (int) temp_ptr->primary_oui[0],
                                     (int) temp_ptr->primary_oui[1],
                                     (int) temp_ptr->primary_oui[2],
                                     (int) temp_ptr->primary_oui[3],
                                     (int) ntohs(temp_ptr->
                                                 primary_subcategory));
                                printf
                                    ("\t Group WifiDirect Client Secondary Device Count = %d\n",
                                     (int) temp_ptr->
                                     wifidirect_secondary_dev_count);
                                array_ptr =
                                    temp_ptr->wifidirect_secondary_dev_info;
                                for (i = 0;
                                     i <
                                     temp_ptr->wifidirect_secondary_dev_count;
                                     i++) {
                                    memcpy(&temp, array_ptr, sizeof(t_u16));
                                    printf
                                        ("\t Group WifiDirect Client Secondary device type = %02d-",
                                         ntohs(temp));
                                    array_ptr += sizeof(temp);
                                    printf("%02X%02X%02X%02X", array_ptr[0],
                                           array_ptr[1], array_ptr[2],
                                           array_ptr[3]);
                                    array_ptr += 4;
                                    memcpy(&temp, array_ptr, sizeof(t_u16));
                                    printf("-%02d\n", ntohs(temp));
                                    array_ptr += sizeof(temp);
                                }
                                /* display device name */
                                array_ptr = temp_ptr->wifidirect_device_name +
                                    temp_ptr->wifidirect_secondary_dev_count *
                                    WPS_DEVICE_TYPE_LEN;
                                printf("\t Group WifiDirect Device Name =  ");
                                memcpy(&temp,
                                       (((t_u8 *) (&temp_ptr->
                                                   wifidirect_device_name_len))
                                        +
                                        temp_ptr->
                                        wifidirect_secondary_dev_count *
                                        WPS_DEVICE_TYPE_LEN), sizeof(t_u16));
                                temp = ntohs(temp);
                                for (i = 0; i < temp; i++)
                                    printf("%c", *array_ptr++);
                                printf("\n");
                                temp_ptr += wifidirect_client_dev_length;
                                temp -= wifidirect_client_dev_length;
                                no_of_wifidirect_clients++;
                                if (temp_ptr)
                                    wifidirect_client_dev_length =
                                        temp_ptr->dev_length;
                            }
                            printf("\n");
                            printf
                                ("\t Group WifiDirect Client Devices count = %d\n",
                                 no_of_wifidirect_clients);
                        }
                        break;
                    case TLV_TYPE_WIFIDIRECT_GROUP_ID:
                        {
                            tlvbuf_wifidirect_group_id *wifidirect_tlv =
                                (tlvbuf_wifidirect_group_id *) ptr;
                            printf("\t Group address - ");
                            print_mac(wifidirect_tlv->group_address);
                            printf("\n");
                            array_ptr = wifidirect_tlv->group_ssid;
                            printf("\t Group ssid =  ");
                            for (i = 0;
                                 (unsigned int) i <
                                 le16_to_cpu(wifidirect_tlv->length)
                                 - (sizeof(tlvbuf_wifidirect_group_id) -
                                    WIFIDIRECT_IE_HEADER_LEN); i++)
                                printf("%c", *array_ptr++);
                            printf("\n");
                        }
                        break;
                    case TLV_TYPE_WIFIDIRECT_GROUP_BSS_ID:
                        {
                            tlvbuf_wifidirect_group_bss_id *wifidirect_tlv =
                                (tlvbuf_wifidirect_group_bss_id *) ptr;
                            printf("\t Group BSS Id - ");
                            print_mac(wifidirect_tlv->group_bssid);
                            printf("\n");
                        }
                        break;
                    case TLV_TYPE_WIFIDIRECT_INTERFACE:
                        {
                            tlvbuf_wifidirect_interface *wifidirect_tlv =
                                (tlvbuf_wifidirect_interface *) ptr;
                            printf("\t Interface Id - ");
                            print_mac(wifidirect_tlv->interface_id);
                            printf("\t Interface count = %d",
                                   (int) wifidirect_tlv->interface_count);
                            for (i = 0; i < wifidirect_tlv->interface_count;
                                 i++) {
                                printf("\n\t Interface address [%d]", i + 1);
                                print_mac(&wifidirect_tlv->
                                          interface_idlist[i * ETH_ALEN]);
                            }
                            printf("\n");
                        }
                        break;
                    case TLV_TYPE_WIFIDIRECT_CHANNEL:
                        {
                            tlvbuf_wifidirect_channel *wifidirect_tlv =
                                (tlvbuf_wifidirect_channel *) ptr;
                            printf("\t Listen Channel Country String \"%c%c\"",
                                   wifidirect_tlv->country_string[0],
                                   wifidirect_tlv->country_string[1]);
                            if (isalpha(wifidirect_tlv->country_string[2]))
                                printf("\"%c\"",
                                       wifidirect_tlv->country_string[2]);
                            printf("\n");
                            printf("\t Listern Channel regulatory class = %d\n",
                                   (int) wifidirect_tlv->regulatory_class);
                            printf("\t Listen Channel number = %d\n",
                                   (int) wifidirect_tlv->channel_number);
                        }
                        break;

                    case TLV_TYPE_WIFIDIRECT_OPCHANNEL:
                        {
                            tlvbuf_wifidirect_channel *wifidirect_tlv =
                                (tlvbuf_wifidirect_channel *) ptr;
                            printf("\t Operating Channel Country String %c%c",
                                   wifidirect_tlv->country_string[0],
                                   wifidirect_tlv->country_string[1]);
                            if (isalpha(wifidirect_tlv->country_string[2]))
                                printf("%c", wifidirect_tlv->country_string[2]);
                            printf("\n");
                            printf
                                ("\t Operating Channel regulatory class = %d\n",
                                 (int) wifidirect_tlv->regulatory_class);
                            printf("\t Operating Channel number = %d\n",
                                   (int) wifidirect_tlv->channel_number);
                        }
                        break;
                    case TLV_TYPE_WIFIDIRECT_INVITATION_FLAG:
                        {
                            tlvbuf_wifidirect_invitation_flag *wifidirect_tlv =
                                (tlvbuf_wifidirect_invitation_flag *) ptr;
                            printf("\t Invitation flag = %d\n",
                                   (int) wifidirect_tlv->
                                   invitation_flag & INVITATION_FLAG_MASK);
                        }
                        break;
                    case TLV_TYPE_WIFIDIRECT_CONFIG_TIMEOUT:
                        {
                            tlvbuf_wifidirect_config_timeout *wifidirect_tlv =
                                (tlvbuf_wifidirect_config_timeout *) ptr;
                            printf("\t GO configuration timeout = %d msec\n",
                                   (int) wifidirect_tlv->group_config_timeout *
                                   10);
                            printf
                                ("\t Client configuration timeout = %d msec\n",
                                 (int) wifidirect_tlv->device_config_timeout *
                                 10);
                        }
                        break;
                    case TLV_TYPE_WIFIDIRECT_EXTENDED_LISTEN_TIME:
                        {
                            tlvbuf_wifidirect_ext_listen_time *wifidirect_tlv =
                                (tlvbuf_wifidirect_ext_listen_time *) ptr;
                            printf("\t Availability Period = %d msec\n",
                                   (int) wifidirect_tlv->availability_period);
                            printf("\t Availability Interval = %d msec\n",
                                   (int) wifidirect_tlv->availability_interval);
                        }
                        break;
                    case TLV_TYPE_WIFIDIRECT_INTENDED_ADDRESS:
                        {
                            tlvbuf_wifidirect_intended_addr *wifidirect_tlv =
                                (tlvbuf_wifidirect_intended_addr *) ptr;
                            printf("\t Intended Interface Address - ");
                            print_mac(wifidirect_tlv->group_address);
                            printf("\n");
                        }
                        break;
                    default:
                        printf("unknown ie=0x%x, len=%d\n", type, len);
                        break;
                    }
                    ptr += len + WIFIDIRECT_IE_HEADER_LEN;
                    ie_len_wifidirect -= len + WIFIDIRECT_IE_HEADER_LEN;
                }

                /* Goto next index, Locate headers */
                printf("WPS settings:\n");
                ie_ptr =
                    (custom_ie *) ((t_u8 *) ie_ptr + sizeof(custom_ie) +
                                   ie_ptr->ie_length);
                ptr = ie_ptr->ie_buffer;
                ie_len_wps = ie_ptr->ie_length;
                if (!wifidir_use_fixed_ie_indices()) {
                    while (memcmp(ptr, wps_oui, sizeof(wps_oui))) {
                        ie_ptr =
                            (custom_ie *) ((t_u8 *) ie_ptr + sizeof(custom_ie) +
                                           ie_ptr->ie_length);
                        ie_len_wps = ie_ptr->ie_length;
                        ptr = ie_ptr->ie_buffer;
                    }
                    ptr += sizeof(wps_oui);
                    ie_len_wifidirect -= sizeof(wps_oui);
                }
                while (ie_len_wps > sizeof(tlvbuf_wps_ie)) {
                    memcpy(&wps_type, ptr, sizeof(t_u16));
                    memcpy(&wps_len, ptr + 2, sizeof(t_u16));
                    endian_convert_tlv_wps_header_in(wps_type, wps_len);
                    switch (wps_type) {
                    case SC_Version:
                        {
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            printf("\t WPS Version = 0x%2x\n",
                                   *(wps_tlv->data));
                        }
                        break;
                    case SC_Simple_Config_State:
                        {
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            printf("\t WPS setupstate = 0x%x\n",
                                   *(wps_tlv->data));
                        }
                        break;
                    case SC_Request_Type:
                        {
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            printf("\t WPS RequestType = 0x%x\n",
                                   *(wps_tlv->data));
                        }
                        break;
                    case SC_Response_Type:
                        {
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            printf("\t WPS ResponseType = 0x%x\n",
                                   *(wps_tlv->data));
                        }
                        break;
                    case SC_Config_Methods:
                        {
                            t_u16 wps_config_methods = 0;
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            memcpy(&wps_config_methods, wps_tlv->data,
                                   sizeof(t_u16));
                            wps_config_methods = ntohs(wps_config_methods);
                            printf("\t WPS SpecConfigMethods = 0x%x\n",
                                   wps_config_methods);
                        }
                        break;
                    case SC_UUID_E:
                        {
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            array_ptr = wps_tlv->data;
                            printf("\t WPS UUID = ");
                            for (i = 0; i < wps_len; i++)
                                printf("%2X ", *array_ptr++);
                            printf("\n");
                        }
                        break;
                    case SC_Primary_Device_Type:
                        {
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            array_ptr = wps_tlv->data;
                            printf("\t WPS Primary Device Type = ");
                            for (i = 0; i < wps_len; i++)
                                printf("%02X ", *array_ptr++);
                            printf("\n");
                        }
                        break;
                    case SC_RF_Band:
                        {
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            printf("\t WPS RF Band = 0x%x\n", *(wps_tlv->data));
                        }
                        break;
                    case SC_Association_State:
                        {
                            t_u16 wps_association_state = 0;
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            memcpy(&wps_association_state, wps_tlv->data,
                                   sizeof(t_u16));
                            printf("\t WPS Association State = 0x%x\n",
                                   wps_association_state);
                        }
                        break;
                    case SC_Configuration_Error:
                        {
                            t_u16 wps_configuration_error = 0;
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            memcpy(&wps_configuration_error, wps_tlv->data,
                                   sizeof(t_u16));
                            wps_configuration_error =
                                ntohs(wps_configuration_error);
                            printf("\t WPS Configuration Error = 0x%x\n",
                                   wps_configuration_error);
                        }
                        break;
                    case SC_Device_Password_ID:
                        {
                            t_u16 wps_device_password_id = 0;
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            memcpy(&wps_device_password_id, wps_tlv->data,
                                   sizeof(t_u16));
                            wps_device_password_id =
                                ntohs(wps_device_password_id);
                            printf("\t WPS Device Password ID = 0x%x\n",
                                   wps_device_password_id);
                        }
                        break;
                    case SC_Device_Name:
                        {
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            array_ptr = wps_tlv->data;
                            printf("\t WPS Device Name = ");
                            for (i = 0; i < wps_len; i++)
                                printf("%c", *array_ptr++);
                            printf("\n");
                        }
                        break;
                    case SC_Manufacturer:
                        {
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            array_ptr = wps_tlv->data;
                            printf("\t WPS Manufacturer = ");
                            for (i = 0; i < wps_len; i++)
                                printf("%c", *array_ptr++);
                            printf("\n");
                        }
                        break;
                    case SC_Model_Name:
                        {
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            array_ptr = wps_tlv->data;
                            printf("\t WPS Model Name = ");
                            for (i = 0; i < wps_len; i++)
                                printf("%c", *array_ptr++);
                            printf("\n");
                        }
                        break;
                    case SC_Model_Number:
                        {
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            array_ptr = wps_tlv->data;
                            printf("\t WPS Model Number = ");
                            for (i = 0; i < wps_len; i++)
                                printf("%d", *array_ptr++);
                            printf("\n");
                        }
                        break;
                    case SC_Serial_Number:
                        {
                            tlvbuf_wps_ie *wps_tlv = (tlvbuf_wps_ie *) ptr;
                            array_ptr = wps_tlv->data;
                            printf("\t WPS Serial Number = ");
                            for (i = 0; i < wps_len; i++)
                                printf("%d", *array_ptr++);
                            printf("\n");
                        }
                        break;
                    default:
                        printf("unknown ie=0x%x, len=%d\n", wps_type, wps_len);
                        break;
                    }
                    ptr += wps_len + sizeof(tlvbuf_wps_ie);
                    ie_len_wps -= wps_len + sizeof(tlvbuf_wps_ie);
                }
            }
        } else {
            printf("ERR:Could not retrieve wifidirect parameters\n");
        }
    }

    free(buf);
    return;
}

/**
 *  @brief Show usage information for the wifidirect_params_config command
 *
 *  $return         N/A
 */
static void
print_wifidirect_params_config_usage(void)
{
    printf("\nUsage : wifidirect_params_config <CONFIG_FILE>\n");
    printf("\nIssue set or get request using parameters in the CONFIG_FILE.\n");
    return;
}

/** 
 *  @brief Creates a wifidirect_params_config request and sends to the driver
 *
 *  Usage: "Usage : wifidirect_params_config <CONFIG_FILE>"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         None 
 */
static void
wifidirectcmd_params_config(int argc, char *argv[])
{
    wifidirect_params_config *param_buf = NULL;
    tlvbuf_wps_ie *new_tlv = NULL;
    char *line = NULL, wifidirect_mac[20];
    FILE *config_file = NULL;
    int i, opt, li = 0, arg_num = 0, ret = 0;
    char *args[30], *pos = NULL;
    t_u8 dev_address[ETH_ALEN], enable_scan;
    t_u8 *buffer = NULL, WPS_primarydevicetype[WPS_DEVICE_TYPE_MAX_LEN];
    t_u16 device_state = 0, tlv_len = 0, max_disc_int, min_disc_int, cmd_len =
        0;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_params_config_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if (argc < 2) {
        printf("ERR:wrong number of arguments.\n");
        print_wifidirect_params_config_usage();
        return;
    }

    cmd_len = sizeof(wifidirect_params_config);
    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);
    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }
    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
    param_buf = (wifidirect_params_config *) buffer;
    param_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG;
    param_buf->seq_num = 0;
    param_buf->result = 0;

    if (argc >= 3) {
        /* Check if file exists */
        config_file = fopen(argv[2], "r");
        if (config_file == NULL) {
            printf("\nERR:Config file can not open.\n");
            goto done;
        }
        line = (char *) malloc(MAX_CONFIG_LINE);
        if (!line) {
            printf("ERR:Cannot allocate memory for line\n");
            goto done;
        }
        memset(line, 0, MAX_CONFIG_LINE);
        param_buf->action = cpu_to_le16(ACTION_SET);

        /* Parse file and process */
        while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) {
            arg_num = parse_line(line, args);

            if (strcmp(args[0], "EnableScan") == 0) {
                if (is_input_valid
                    (WIFIDIRECT_ENABLE_SCAN, arg_num - 1, args + 1)
                    != SUCCESS) {
                    goto done;

                }
                enable_scan = (t_u8) atoi(args[1]);
                /* Append a new TLV */
                tlv_len = sizeof(tlvbuf_wps_ie) + sizeof(t_u8);
                new_tlv = (tlvbuf_wps_ie *) (buffer + cmd_len);
                cmd_len += tlv_len;
                /* Set TLV fields */
                new_tlv->tag = MRVL_WIFIDIRECT_SCAN_ENABLE_TLV_ID;
                new_tlv->length = tlv_len - 2 * sizeof(t_u16);
                memcpy(new_tlv->data, &enable_scan, sizeof(t_u8));
                endian_convert_tlv_header_out(new_tlv);

            } else if (strcmp(args[0], "ScanPeerDeviceId") == 0) {
                strncpy(wifidirect_mac, args[1], 20 - 1);
                if ((ret = mac2raw(wifidirect_mac, dev_address)) != SUCCESS) {
                    printf("ERR: %s Address \n",
                           ret == FAILURE ? "Invalid MAC" : ret ==
                           WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" :
                           "Multicast");
                    goto done;
                }
                /* Append a new TLV */
                tlv_len = sizeof(tlvbuf_wps_ie) + ETH_ALEN;
                new_tlv = (tlvbuf_wps_ie *) (buffer + cmd_len);
                cmd_len += tlv_len;
                /* Set TLV fields */
                new_tlv->tag = MRVL_WIFIDIRECT_PEER_DEVICE_TLV_ID;
                new_tlv->length = tlv_len - 2 * sizeof(t_u16);
                memcpy(new_tlv->data, dev_address, ETH_ALEN);
                endian_convert_tlv_header_out(new_tlv);

            } else if (strcmp(args[0], "MinDiscoveryInterval") == 0) {
                if (is_input_valid
                    (WIFIDIRECT_MINDISCOVERYINT, arg_num - 1,
                     args + 1) != SUCCESS) {
                    goto done;
                }
                min_disc_int = cpu_to_le16(atoi(args[1]));
            } else if (strcmp(args[0], "MaxDiscoveryInterval") == 0) {
                if (is_input_valid
                    (WIFIDIRECT_MAXDISCOVERYINT, arg_num - 1,
                     args + 1) != SUCCESS) {
                    goto done;
                }
                max_disc_int = cpu_to_le16(atoi(args[1]));

                /* Append a new TLV */
                tlv_len = sizeof(tlvbuf_wps_ie) + 2 * sizeof(t_u16);
                new_tlv = (tlvbuf_wps_ie *) (buffer + cmd_len);
                cmd_len += tlv_len;
                /* Set TLV fields */
                new_tlv->tag = MRVL_WIFIDIRECT_DISC_PERIOD_TLV_ID;
                new_tlv->length = tlv_len - 2 * sizeof(t_u16);
                memcpy(&new_tlv->data, &min_disc_int, sizeof(t_u16));
                memcpy((((t_u8 *) & new_tlv->data) + sizeof(t_u16)),
                       &max_disc_int, sizeof(t_u16));
                endian_convert_tlv_header_out(new_tlv);

            } else if (strcmp(args[0], "ScanRequestDeviceType") == 0) {
                if (is_input_valid
                    (WIFIDIRECT_WPSPRIMARYDEVICETYPE, arg_num - 1, args + 1)
                    != SUCCESS) {
                    goto done;
                }
                for (i = 0; i < WPS_DEVICE_TYPE_MAX_LEN; i++)
                    WPS_primarydevicetype[i] = (t_u8) A2HEXDECIMAL(args[i + 1]);

                /* Append a new TLV */
                tlv_len = sizeof(tlvbuf_wps_ie) + WPS_DEVICE_TYPE_MAX_LEN;
                new_tlv = (tlvbuf_wps_ie *) (buffer + cmd_len);
                cmd_len += tlv_len;
                /* Set TLV fields */
                new_tlv->tag = MRVL_WIFIDIRECT_SCAN_REQ_DEVICE_TLV_ID;
                new_tlv->length = tlv_len - 2 * sizeof(t_u16);
                memcpy(&new_tlv->data, WPS_primarydevicetype,
                       WPS_DEVICE_TYPE_MAX_LEN);
                endian_convert_tlv_header_out(new_tlv);

            } else if (strcmp(args[0], "DeviceState") == 0) {
                if (is_input_valid
                    (WIFIDIRECT_DEVICE_STATE, arg_num - 1, args + 1)
                    != SUCCESS) {
                    goto done;
                }
                device_state = cpu_to_le16((t_u16) atoi(args[1]));

                /* Append a new TLV */
                tlv_len = sizeof(tlvbuf_wps_ie) + sizeof(t_u16);
                new_tlv = (tlvbuf_wps_ie *) (buffer + cmd_len);
                cmd_len += tlv_len;
                /* Set TLV fields */
                new_tlv->tag = MRVL_WIFIDIRECT_DEVICE_STATE_TLV_ID;
                new_tlv->length = tlv_len - 2 * sizeof(t_u16);
                memcpy(new_tlv->data, &device_state, sizeof(t_u16));
                endian_convert_tlv_header_out(new_tlv);
            }
        }
    }

    param_buf->size = cmd_len;
    /* Send collective command */
    wifidirect_ioctl((t_u8 *) buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER);

    /* Process response */
    if (argc < 3) {
        /* Verify response */
        if (param_buf->cmd_code !=
            (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | WIFIDIRECTCMD_RESP_CHECK)) {
            printf("ERR:Corrupted response!\n");
            goto done;
        }
        /* Print response */
        if (param_buf->result == CMD_SUCCESS) {
            param_buf = (wifidirect_params_config *) buffer;
            new_tlv = (tlvbuf_wps_ie *) param_buf->wifidirect_tlv;
            tlv_len =
                param_buf->size - (sizeof(wifidirect_params_config) -
                                   BUF_HEADER_SIZE);
            if (tlv_len > sizeof(tlvbuf_wps_ie))
                printf("WifiDirect Parameter settings: \n");
            else
                printf("WifiDirect Parameter settings are not received.\n");
            while (tlv_len > sizeof(tlvbuf_wps_ie)) {
                endian_convert_tlv_header_in(new_tlv);
                switch (new_tlv->tag) {
                case MRVL_WIFIDIRECT_SCAN_ENABLE_TLV_ID:
                    {
                        enable_scan = *((t_u8 *) & new_tlv->data);
                        printf("\t Scan %s\n",
                               (enable_scan == 1) ? "enabled." : "disabled.");
                    }
                    break;
                case MRVL_WIFIDIRECT_PEER_DEVICE_TLV_ID:
                    {
                        memcpy(dev_address, new_tlv->data, ETH_ALEN);
                        printf("\t Peer Device ID : ");
                        print_mac(dev_address);
                        printf("\n");
                    }
                    break;
                case MRVL_WIFIDIRECT_DISC_PERIOD_TLV_ID:
                    {
                        t_u16 temp;
                        memcpy(&temp, &new_tlv->data, sizeof(t_u16));
                        printf("\t Minimum Discovery Interval : %d\n",
                               le16_to_cpu(temp));
                        memcpy(&temp,
                               ((t_u8 *) & new_tlv->data) + sizeof(t_u16),
                               sizeof(t_u16));
                        printf("\t Maximum Discovery Interval : %d\n",
                               le16_to_cpu(temp));
                    }
                    break;
                case MRVL_WIFIDIRECT_SCAN_REQ_DEVICE_TLV_ID:
                    {
                        memcpy(WPS_primarydevicetype, &new_tlv->data,
                               WPS_DEVICE_TYPE_MAX_LEN);
                        printf("\tType: %02x:%02x\n",
                               (unsigned int) WPS_primarydevicetype[0],
                               (unsigned int) WPS_primarydevicetype[1]);
                        printf("\tOUI: %02x:%02x:%02x:%02x\n",
                               (unsigned int) WPS_primarydevicetype[2],
                               (unsigned int) WPS_primarydevicetype[3],
                               (unsigned int) WPS_primarydevicetype[4],
                               (unsigned int) WPS_primarydevicetype[5]);
                        printf("\tSubType: %02x:%02x\n",
                               (unsigned int) WPS_primarydevicetype[6],
                               (unsigned int) WPS_primarydevicetype[7]);
                    }
                    break;
                case MRVL_WIFIDIRECT_DEVICE_STATE_TLV_ID:
                    {
                        memcpy(&device_state, &new_tlv->data, sizeof(t_u16));
                        printf("\t Device State %d\n",
                               le16_to_cpu(device_state));
                    }
                    break;
                default:
                    printf("Unknown ie=0x%x, len=%d\n", new_tlv->tag,
                           new_tlv->length);
                    break;
                }
                tlv_len -= new_tlv->length + sizeof(tlvbuf_wps_ie);
                new_tlv =
                    (tlvbuf_wps_ie *) (((t_u8 *) new_tlv) + new_tlv->length +
                                       sizeof(tlvbuf_wps_ie));
            }
        } else {
            printf("ERR:Could not retrieve wifidirect parameters.\n");
        }
    }

  done:
    if (config_file)
        fclose(config_file);
    if (line)
        free(line);
    if (buffer)
        free(buffer);
    return;
}

/**
 *  @brief Show usage information for the wifidirect_action_frame command
 *
 *  $return         N/A
 */
static void
print_wifidirect_action_frame_usage(void)
{
    printf("\nUsage : wifidirect_action_frame <CONFIG_FILE> |"
           " [<PeerAddr> <Category> <OUISubtype> <DialogToken>]\n");
    printf("\nAction frame is sent using parameters in the CONFIG_FILE "
           "or parameters specified on command line.\n");
    return;
}

/** 
 *  @brief Creates a wifidirect_action_frame request and sends to the driver
 *
 *  Usage: "Usage : wifidirect_action_frame <CONFIG_FILE> |
 *                  [<PeerAddr> <Category> <OUISubtype> <DialogToken>]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         None 
 */
static void
wifidirectcmd_action_frame(int argc, char *argv[])
{
    wifidirect_action_frame *action_buf = NULL;
    char *line = NULL, wifidirect_mac[20];
    FILE *config_file = NULL;
    int i, opt, li = 0, arg_num = 0, ret = 0, cmd_found = 0;
    char *args[30], *pos = NULL;
    t_u8 dev_address[ETH_ALEN];
    t_u8 *buffer = NULL;
    t_u16 ie_len = 0, cmd_len = 0;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_action_frame_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if ((argc != 3) && (argc != 6)) {
        printf("ERR:wrong number of arguments.\n");
        print_wifidirect_action_frame_usage();
        return;
    }

    cmd_len = sizeof(wifidirect_action_frame);
    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);
    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }
    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
    action_buf = (wifidirect_action_frame *) buffer;
    action_buf->cmd_code = HostCmd_CMD_802_11_ACTION_FRAME;
    action_buf->seq_num = 0;
    action_buf->result = 0;

    /* Check if file exists */
    config_file = fopen(argv[2], "r");
    if (config_file && argc == 3) {
        line = (char *) malloc(MAX_CONFIG_LINE);
        if (!line) {
            printf("ERR:Cannot allocate memory for line\n");
            goto done;
        }

        /* Parse file and process */
        while (config_get_line(line, MAX_CONFIG_LINE, config_file, &li, &pos)) {
            arg_num = parse_line(line, args);

            if (strcmp(args[0], argv[1]) == 0) {
                cmd_found = 1;
            }
            if (cmd_found == 0)
                continue;

            if (strcmp(args[0], "}") == 0) {
                cmd_found = 0;
            } else if (strcmp(args[0], "Category") == 0) {
                if (is_input_valid(WIFIDIRECT_CATEGORY, arg_num - 1, args + 1)
                    != SUCCESS) {
                    goto done;

                }
                action_buf->category = (t_u8) atoi(args[1]);

            } else if (strcmp(args[0], "PeerAddr") == 0) {
                strncpy(wifidirect_mac, args[1], 20);
                if ((ret = mac2raw(wifidirect_mac, dev_address)) != SUCCESS) {
                    printf("ERR: %s Address \n",
                           ret == FAILURE ? "Invalid MAC" : ret ==
                           WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" :
                           "Multicast");
                    goto done;
                }
                memcpy(action_buf->peer_mac_addr, dev_address, ETH_ALEN);
            } else if (strcmp(args[0], "Action") == 0) {
                if (is_input_valid(WIFIDIRECT_ACTION, arg_num - 1, args + 1)
                    != SUCCESS) {
                    goto done;
                }
                action_buf->action = (t_u8) A2HEXDECIMAL(args[1]);

            } else if (strcmp(args[0], "DialogToken") == 0) {
                if (is_input_valid
                    (WIFIDIRECT_DIALOGTOKEN, arg_num - 1, args + 1)
                    != SUCCESS) {
                    goto done;
                }
                action_buf->dialog_taken = (t_u8) atoi(args[1]);

            } else if (strcmp(args[0], "OUI") == 0) {
                if (is_input_valid(WIFIDIRECT_OUI, arg_num - 1, args + 1)
                    != SUCCESS) {
                    goto done;
                }
                for (i = 0; i < arg_num - 1; i++)
                    action_buf->oui[i] = A2HEXDECIMAL(args[i + 1]);
            } else if (strcmp(args[0], "OUIType") == 0) {
                if (is_input_valid(WIFIDIRECT_OUITYPE, arg_num - 1, args + 1)
                    != SUCCESS) {
                    goto done;
                }
                action_buf->oui_type = (t_u8) atoi(args[1]);
            } else if (strcmp(args[0], "OUISubType") == 0) {
                if (is_input_valid(WIFIDIRECT_OUISUBTYPE, arg_num - 1, args + 1)
                    != SUCCESS) {
                    goto done;
                }
                action_buf->oui_sub_type = (t_u8) atoi(args[1]);
            }
        }
        fclose(config_file);
        config_file = NULL;

        /* Now, read IE parameters from file */
        wifidirect_file_params_config(argv[2], argv[1], action_buf->ie_list,
                                      &ie_len, NULL);
        if (ie_len >= MRVDRV_SIZE_OF_CMD_BUFFER) {
            printf("ERR:Too much data in configuration file %s.\n", argv[2]);
            free(buffer);
            return;
        }
        cmd_len += ie_len;
    } else {
        if (argc == 3) {
            printf("ERR:Can not open config file.\n");
            goto done;
        }
        strncpy(wifidirect_mac, argv[2], 20);
        if ((ret = mac2raw(wifidirect_mac, dev_address)) != SUCCESS) {
            printf("ERR: %s Address \n",
                   ret == FAILURE ? "Invalid MAC" : ret ==
                   WIFIDIRECT_RET_MAC_BROADCAST ? "Broadcast" : "Multicast");
            goto done;
        }
        memcpy(action_buf->peer_mac_addr, dev_address, ETH_ALEN);

        if (is_input_valid(WIFIDIRECT_CATEGORY, 1, &argv[3])
            != SUCCESS) {
            goto done;
        }
        action_buf->category = (t_u8) atoi(argv[3]);

        if (is_input_valid(WIFIDIRECT_OUISUBTYPE, 1, &argv[4])
            != SUCCESS) {
            goto done;
        }
        action_buf->oui_sub_type = (t_u8) atoi(argv[4]);

        if (is_input_valid(WIFIDIRECT_DIALOGTOKEN, 1, &argv[5])
            != SUCCESS) {
            goto done;
        }
        action_buf->dialog_taken = (t_u8) atoi(argv[5]);

        action_buf->action = 0;
        action_buf->oui[0] = 0x50;
        action_buf->oui[1] = 0x6F;
        action_buf->oui[2] = 0x9A;
        action_buf->oui_type = OUI_TYPE_WFA_WIFIDIRECT;
    }
    action_buf->size = cmd_len;
#ifdef DEBUG
    /* Debug print */
    hexdump(buffer, cmd_len, ' ');
#endif
    /* Send collective command */
    wifidirect_ioctl((t_u8 *) buffer, &cmd_len, cmd_len);

  done:
    if (config_file)
        fclose(config_file);
    if (line)
        free(line);
    if (buffer)
        free(buffer);
    return;
}

/**
 *  @brief Show usage information for the wifidirect status command
 *
 *  $return         N/A
 */
static void
print_wifidirect_status_usage(void)
{
    printf("\nUsage : wifidirect_mode [STATUS]");
    printf("\nOptions: STATUS :     0 - stop wifidirect status");
    printf("\n                      1 - start wifidirect status");
    printf("\n                      2 - start wifidirect group owner mode");
    printf("\n                      3 - start wifidirect client mode");
    printf("\n                      4 - start wifidirect find phase");
    printf("\n                      5 - stop  wifidirect find phase");
    printf("\n                  empty - get current wifidirect status\n");
    return;
}

/** 
 *  @brief Creates wifidirect mode start or stop request and send to driver
 *
 *   Usage: "Usage : wifidirect_mode [STATUS]"
 *
 *   Options: STATUS :     0 - start wifidirect status
 *                         1 - stop  wifidirect status
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         N/A
 */
static void
wifidirectcmd_status(int argc, char *argv[])
{
    int opt, ret;
    t_u16 data;
    t_u16 cmd_len = 0;
    t_u8 *buffer = NULL;
    wifidirect_mode_config *cmd_buf = NULL;
    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_status_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;
    /* Check arguments */
    if (argc < 2) {
        printf("ERR:wrong arguments.\n");
        print_wifidirect_status_usage();
        return;
    }
    if (argc == 3) {
        if ((ISDIGIT(argv[2]) == 0) || (atoi(argv[2]) < 0) ||
            (atoi(argv[2]) >= 0xFF)) {
            printf
                ("ERR:Illegal wifidirect mode %s. Must be in range from '0' to '5'.\n",
                 argv[2]);
            print_wifidirect_status_usage();
            return;
        }
        data = (t_u16) atoi(argv[2]);
    }

    /* send hostcmd now */
    cmd_len = sizeof(wifidirect_mode_config);
    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);
    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        return;
    }

    cmd_buf = (wifidirect_mode_config *) buffer;
    cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_MODE_CONFIG;
    cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
    cmd_buf->seq_num = 0;
    cmd_buf->result = 0;

    if (argc == 2) {
        cmd_buf->action = ACTION_GET;
    } else {
        cmd_buf->action = cpu_to_le16(ACTION_SET);
        cmd_buf->mode = cpu_to_le16(data);
    }
    ret =
        wifidirect_ioctl((t_u8 *) buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER);
    if (ret != SUCCESS) {
        printf("Error executing wifidirect mode command\n");
        return;
    }

    data = le16_to_cpu(cmd_buf->mode);
    switch (data) {
    case 0:
        printf("Wifidirect Device Mode = Not Configured\n");
        break;
    case 1:
        printf("Wifidirect Device Mode = Device\n");
        break;
    case 2:
        printf("Wifidirect Device Mode = Wifidirect Group Owner (GO)\n");
        break;
    case 3:
        printf("Wifidirect Device Mode = Wifidirect Group Client (GC)\n");
        break;
    default:
        printf("Wifidirect Device Mode = Not specified\n");
        break;
    }
    return;
}

/**
 *  @brief Show usage information for the wifidirect discovery period command
 *
 *  @return         N/A
 */
static void
print_wifidirect_cfg_discovery_period_usage(void)
{
    printf
        ("Usage : wifidirect_cfg_discovery_period [<MinDiscPeriod> <MaxDiscPeriod>]\n");
    printf
        ("For 'Set' both MinDiscPeriod and MaxDiscPeriod should be specified.\n");
    printf("If no parameter is given, 'get' is performed.\n");
    return;
}

/** 
 *  @brief Set/get wifidirect discovery period
 *
 *  Usage: "Usage : wifidirect_cfg_discovery_period [<MinDiscPeriod> <MaxDiscPeriod>]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         None 
 */
static void
wifidirect_cfg_cmd_discovery_period(int argc, char *argv[])
{
    wifidirect_params_config *cmd_buf = NULL;
    tlvbuf_wifidirect_discovery_period *tlv = NULL;
    t_u8 *buffer = NULL;
    t_u16 cmd_len = 0;
    int opt, ret = 0;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_cfg_discovery_period_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if ((argc != 2) && (argc != 4)) {
        printf("ERR:wrong number of arguments.\n");
        print_wifidirect_cfg_discovery_period_usage();
        return;
    } else if ((argc > 2) &&
               ((is_input_valid(WIFIDIRECT_MINDISCOVERYINT, 1, &argv[2]) !=
                 SUCCESS) ||
                (is_input_valid(WIFIDIRECT_MAXDISCOVERYINT, 1, &argv[3]) !=
                 SUCCESS))) {
        print_wifidirect_cfg_discovery_period_usage();
        return;
    }

    cmd_len =
        sizeof(wifidirect_params_config) +
        sizeof(tlvbuf_wifidirect_discovery_period);

    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);

    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }

    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);

    cmd_buf = (wifidirect_params_config *) buffer;
    tlv =
        (tlvbuf_wifidirect_discovery_period *) (buffer +
                                                sizeof
                                                (wifidirect_params_config));

    cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG;
    cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
    cmd_buf->seq_num = 0;
    cmd_buf->result = 0;

    tlv->tag = MRVL_WIFIDIRECT_DISC_PERIOD_TLV_ID;
    tlv->length =
        sizeof(tlvbuf_wifidirect_discovery_period) - MRVL_TLV_HEADER_SIZE;

    if (argc == 2) {
        cmd_buf->action = ACTION_GET;
    } else {
        cmd_buf->action = cpu_to_le16(ACTION_SET);
        tlv->min_disc_interval = cpu_to_le16((t_u16) atoi(argv[2]));
        tlv->max_disc_interval = cpu_to_le16((t_u16) atoi(argv[3]));
    }
    endian_convert_tlv_header_out(tlv);

#ifdef DEBUG
    hexdump(buffer, cmd_len, ' ');
#endif

    ret =
        wifidirect_ioctl((t_u8 *) buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER);
    endian_convert_tlv_header_in(tlv);

#ifdef DEBUG
    hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' ');
#endif

    /* Process Response */
    if (ret == SUCCESS) {
        /* Verify response */
        if (cmd_buf->cmd_code !=
            (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | WIFIDIRECTCMD_RESP_CHECK)) {
            printf("ERR:Corrupted response!\n");
            goto done;
        }
        /* Print response */
        if (cmd_buf->result == CMD_SUCCESS) {
            if (argc == 2) {
                printf("Min Discovery period = %d\n",
                       le16_to_cpu(tlv->min_disc_interval));
                printf("Max discovery period = %d\n",
                       le16_to_cpu(tlv->max_disc_interval));
            } else {
                printf("Discovery period setting successful!\n");
            }
        } else {
            if (argc == 2) {
                printf("ERR:Couldn't get min and max discovery period!\n");
            } else {
                printf("ERR:Couldn't set min and max discovery period!\n");
            }
        }
    } else {
        printf("ERR:Command sending failed!\n");
    }
  done:
    if (buffer)
        free(buffer);
    return;
}

/**
 *  @brief Show usage information for the wifidirect Intent command
 *
 *  @return         N/A
 */
static void
print_wifidirect_cfg_intent_usage(void)
{
    printf("Usage : wifidirect_cfg_intent [IntentValue]\n");
    printf
        ("If IntentValue parameter is provided, 'set' is performed otherwise 'get' is performed.\n");
    return;
}

/** 
 *  @brief Set/get wifidirect Intent
 *
 *  Usage: "Usage : wifidirect_cfg_intent [IntentValue]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         None 
 */
static void
wifidirect_cfg_cmd_intent(int argc, char *argv[])
{
    wifidirect_params_config *cmd_buf = NULL;
    tlvbuf_wifidirect_intent *tlv = NULL;
    t_u8 *buffer = NULL;
    t_u16 cmd_len = 0;
    int opt, ret = 0;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_cfg_intent_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if (argc < 2) {
        printf("ERR: Wrong number of arguments!\n");
        print_wifidirect_cfg_intent_usage();
        return;
    } else if ((argc > 2) &&
               (is_input_valid(WIFIDIRECT_INTENT, argc - 2, argv + 2) !=
                SUCCESS)) {
        print_wifidirect_cfg_intent_usage();
        return;
    }
    cmd_len =
        sizeof(wifidirect_params_config) + sizeof(tlvbuf_wifidirect_intent);

    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);

    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }

    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);

    cmd_buf = (wifidirect_params_config *) buffer;
    tlv =
        (tlvbuf_wifidirect_intent *) (buffer +
                                      sizeof(wifidirect_params_config));

    cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG;
    cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
    cmd_buf->seq_num = 0;
    cmd_buf->result = 0;

    tlv->tag = MRVL_WIFIDIRECT_INTENT_TLV_ID;
    tlv->length = sizeof(tlvbuf_wifidirect_intent) - MRVL_TLV_HEADER_SIZE;

    if (argc == 2) {
        cmd_buf->action = ACTION_GET;
    } else {
        cmd_buf->action = cpu_to_le16(ACTION_SET);
        tlv->intent = (t_u8) atoi(argv[2]);
    }
    endian_convert_tlv_header_out(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len, ' ');
#endif
    ret =
        wifidirect_ioctl((t_u8 *) buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER);
    endian_convert_tlv_header_in(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' ');
#endif
    /* Process Response */
    if (ret == SUCCESS) {
        /* Verify response */
        if (cmd_buf->cmd_code !=
            (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | WIFIDIRECTCMD_RESP_CHECK)) {
            printf("ERR:Corrupted response!\n");
            goto done;
        }
        /* Print response */
        if (cmd_buf->result == CMD_SUCCESS) {
            if (argc == 2) {
                printf("Intent Value = %d\n", (int) tlv->intent);
            } else {
                printf("Intent value setting successful!\n");
            }
        } else {
            if (argc == 2) {
                printf("ERR:Couldn't get Intent value!\n");
            } else {
                printf("ERR:Couldn't set Intent value!\n");
            }
        }
    } else {
        printf("ERR:Command sending failed!\n");
    }
  done:
    if (buffer)
        free(buffer);
    return;
}

/**
 *  @brief Show usage information for the wifidirect Listen Channel command
 *
 *  @return         N/A
 */
static void
print_wifidirect_cfg_listen_channel_usage(void)
{
    printf("Usage : wifidirect_cfg_listen_channel [ListenChannel]\n");
    printf
        ("If ListenChannel parameter is provided, 'set' is performed otherwise 'get' is performed.\n");
    return;
}

/** 
 *  @brief Set/get wifidirect ListenChannel
 *
 *  Usage: "Usage : wifidirect_cfg_listen_channel [ListenChannel]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         None 
 */
static void
wifidirect_cfg_cmd_listen_channel(int argc, char *argv[])
{
    wifidirect_params_config *cmd_buf = NULL;
    tlvbuf_wifidirect_listen_channel *tlv = NULL;
    t_u8 *buffer = NULL;
    t_u16 cmd_len = 0;
    int opt, ret = 0;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_cfg_listen_channel_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if (argc < 2) {
        printf("ERR: Wrong number of arguments!\n");
        print_wifidirect_cfg_listen_channel_usage();
        return;
    } else if ((argc > 2) &&
               (is_input_valid(CHANNEL, argc - 2, argv + 2) != SUCCESS)) {
        print_wifidirect_cfg_listen_channel_usage();
        return;
    }
    cmd_len =
        sizeof(wifidirect_params_config) +
        sizeof(tlvbuf_wifidirect_listen_channel);

    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);

    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }

    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);

    cmd_buf = (wifidirect_params_config *) buffer;
    tlv =
        (tlvbuf_wifidirect_listen_channel *) (buffer +
                                              sizeof(wifidirect_params_config));

    cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG;
    cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
    cmd_buf->seq_num = 0;
    cmd_buf->result = 0;

    tlv->tag = MRVL_WIFIDIRECT_LISTEN_CHANNEL_TLV_ID;
    tlv->length =
        sizeof(tlvbuf_wifidirect_listen_channel) - MRVL_TLV_HEADER_SIZE;

    if (argc == 2) {
        cmd_buf->action = ACTION_GET;
    } else {
        cmd_buf->action = cpu_to_le16(ACTION_SET);
        tlv->listen_channel = (t_u8) atoi(argv[2]);
    }
    endian_convert_tlv_header_out(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len, ' ');
#endif
    ret =
        wifidirect_ioctl((t_u8 *) buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER);
    endian_convert_tlv_header_in(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' ');
#endif
    /* Process Response */
    if (ret == SUCCESS) {
        /* Verify response */
        if (cmd_buf->cmd_code !=
            (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | WIFIDIRECTCMD_RESP_CHECK)) {
            printf("ERR:Corrupted response!\n");
            goto done;
        }
        /* Print response */
        if (cmd_buf->result == CMD_SUCCESS) {
            if (argc == 2) {
                printf("Listen Channel = %d\n", (int) tlv->listen_channel);
            } else {
                printf("Listen Channel setting successful!\n");
            }
        } else {
            if (argc == 2) {
                printf("ERR:Couldn't get Listen Channel!\n");
            } else {
                printf("ERR:Couldn't set Listen Channel!\n");
            }
        }
    } else {
        printf("ERR:Command sending failed!\n");
    }
  done:
    if (buffer)
        free(buffer);
    return;
}

/**
 *  @brief Show usage information for the wifidirect Operating Channel command
 *
 *  @return         N/A
 */
static void
print_wifidirect_cfg_op_channel_usage(void)
{
    printf("Usage : wifidirect_cfg_op_channel [OperatingChannel]\n");
    printf
        ("If OperatingChannel parameter is provided, 'set' is performed otherwise 'get' is performed.\n");
    return;
}

/** 
 *  @brief Set/get wifidirect OperatingChannel
 *
 *  Usage: "Usage : wifidirect_cfg_op_channel [OperatingChannel]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         None 
 */
static void
wifidirect_cfg_cmd_op_channel(int argc, char *argv[])
{
    wifidirect_params_config *cmd_buf = NULL;
    tlvbuf_wifidirect_operating_channel *tlv = NULL;
    t_u8 *buffer = NULL;
    t_u16 cmd_len = 0;
    int opt, ret = 0;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_cfg_op_channel_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if (argc < 2) {
        printf("ERR: Wrong number of arguments!\n");
        print_wifidirect_cfg_op_channel_usage();
        return;
    } else if ((argc > 2) &&
               (is_input_valid(CHANNEL, argc - 2, argv + 2) != SUCCESS)) {
        print_wifidirect_cfg_op_channel_usage();
        return;
    }
    cmd_len =
        sizeof(wifidirect_params_config) +
        sizeof(tlvbuf_wifidirect_operating_channel);

    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);

    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }

    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);

    cmd_buf = (wifidirect_params_config *) buffer;
    tlv =
        (tlvbuf_wifidirect_operating_channel *) (buffer +
                                                 sizeof
                                                 (wifidirect_params_config));

    cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG;
    cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
    cmd_buf->seq_num = 0;
    cmd_buf->result = 0;

    tlv->tag = MRVL_WIFIDIRECT_OPERATING_CHANNEL_TLV_ID;
    tlv->length =
        sizeof(tlvbuf_wifidirect_operating_channel) - MRVL_TLV_HEADER_SIZE;

    if (argc == 2) {
        cmd_buf->action = ACTION_GET;
    } else {
        cmd_buf->action = cpu_to_le16(ACTION_SET);
        tlv->operating_channel = (t_u8) atoi(argv[2]);
    }
    endian_convert_tlv_header_out(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len, ' ');
#endif
    ret =
        wifidirect_ioctl((t_u8 *) buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER);
    endian_convert_tlv_header_in(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' ');
#endif
    /* Process Response */
    if (ret == SUCCESS) {
        /* Verify response */
        if (cmd_buf->cmd_code !=
            (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | WIFIDIRECTCMD_RESP_CHECK)) {
            printf("ERR:Corrupted response!\n");
            goto done;
        }
        /* Print response */
        if (cmd_buf->result == CMD_SUCCESS) {
            if (argc == 2) {
                printf("Operating Channel = %d\n",
                       (int) tlv->operating_channel);
            } else {
                printf("Operating Channel setting successful!\n");
            }
        } else {
            if (argc == 2) {
                printf("ERR:Couldn't get Operating Channel!\n");
            } else {
                printf("ERR:Couldn't set Operating Channel!\n");
            }
        }
    } else {
        printf("ERR:Command sending failed!\n");
    }
  done:
    if (buffer)
        free(buffer);
    return;
}

/**
 *  @brief Show usage information for the wifidirect Invitation List command
 *
 *  @return         N/A
 */
static void
print_wifidirect_cfg_invitation_list_usage(void)
{
    printf("\nUsage : wifidirect_cfg_invitation_list [mac_addr]");
    printf
        ("\nIf mac_addr parameter is provided, 'set' is performed otherwise 'get' is performed.\n");
    return;
}

/** 
 *  @brief Set/get wifidirect InvitationList
 *
 *  Usage: "Usage : wifidirect_cfg_invitation_list [mac_addr]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         None 
 */
static void
wifidirect_cfg_cmd_invitation_list(int argc, char *argv[])
{
    wifidirect_params_config *cmd_buf = NULL;
    tlvbuf_wifidirect_invitation_list *tlv = NULL;
    t_u8 *buffer = NULL;
    t_u16 cmd_len = 0;
    int opt, ret = 0, ctr = 1;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_cfg_invitation_list_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if ((argc < 2) || (argc > 3)) {
        printf("ERR:Wrong number of arguments!\n");
        print_wifidirect_cfg_invitation_list_usage();
        return;
    }

    cmd_len =
        sizeof(wifidirect_params_config) +
        sizeof(tlvbuf_wifidirect_invitation_list);

    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);

    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }

    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);

    cmd_buf = (wifidirect_params_config *) buffer;
    tlv =
        (tlvbuf_wifidirect_invitation_list *) (buffer +
                                               sizeof
                                               (wifidirect_params_config));

    cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG;
    cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
    cmd_buf->seq_num = 0;
    cmd_buf->result = 0;

    tlv->tag = MRVL_WIFIDIRECT_INVITATION_LIST_TLV_ID;
    tlv->length =
        sizeof(tlvbuf_wifidirect_invitation_list) - MRVL_TLV_HEADER_SIZE;

    if (argc == 2) {
        cmd_buf->action = ACTION_GET;
        cmd_len += (WIFIDIRECT_INVITATION_LIST_MAX - 1) * ETH_ALEN;
    } else {
        cmd_buf->action = cpu_to_le16(ACTION_SET);
        if ((ret = mac2raw(argv[2], tlv->inv_peer_addr)) != SUCCESS) {
            printf("ERR:Invalid MAC address %s\n", argv[2]);
            goto done;
        }
    }
    endian_convert_tlv_header_out(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len, ' ');
#endif
    ret =
        wifidirect_ioctl((t_u8 *) buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER);
    endian_convert_tlv_header_in(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' ');
#endif
    /* Process Response */
    if (ret == SUCCESS) {
        /* Verify response */
        if (cmd_buf->cmd_code !=
            (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | WIFIDIRECTCMD_RESP_CHECK)) {
            printf("ERR:Corrupted response!\n");
            goto done;
        }
        /* Print response */
        if (cmd_buf->result == CMD_SUCCESS) {
            if (argc == 2) {
                /* reusing variable cmd_len */
                cmd_len = tlv->length;
                if (cmd_len > 0) {
                    printf("Invitation List =>");
                    while (cmd_len >= ETH_ALEN) {
                        if (memcmp
                            (tlv->inv_peer_addr, "\x00\x00\x00\x00\x00\x00",
                             ETH_ALEN)) {
                            printf("\n\t [%d] ", ctr++);
                            print_mac(tlv->inv_peer_addr);
                        }
                        cmd_len -= ETH_ALEN;
                        tlv =
                            (tlvbuf_wifidirect_invitation_list
                             *) (((t_u8 *) (tlv)) + ETH_ALEN);
                    }
                    if (ctr == 1)
                        printf(" empty.");
                } else
                    printf("Invitation List is empty.\n");
                printf("\n");
            } else {
                printf("Invitation List setting successful!\n");
            }
        } else {
            if (argc == 2) {
                printf("ERR:Couldn't get Invitation List!\n");
            } else {
                printf("ERR:Couldn't set Invitation List!\n");
            }
        }
    } else {
        printf("ERR:Command sending failed!\n");
    }
  done:
    if (buffer)
        free(buffer);
    return;
}

/**
 *  @brief Show usage information for the wifidirect noa config command
 *
 *  @return         N/A
 */
static void
print_wifidirect_cfg_noa_usage(void)
{
    printf
        ("Usage : wifidirect_cfg_noa <enable|disable> <index> [<counttype> <duration> <interval>]\n");
    printf
        ("If NOA parameters are provided, 'set' is performed otherwise 'get' is performed.\n");
    return;
}

/** 
 *  @brief Set/get wifidirect NoA parameters
 *
 *  Usage: "Usage : wifidirect_cfg_noa <enable|disable> <index> [<counttype> <duration> <interval>]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         None 
 */
static void
wifidirect_cfg_cmd_noa(int argc, char *argv[])
{
    wifidirect_params_config *cmd_buf = NULL;
    tlvbuf_wifidirect_noa_config *tlv = NULL;
    t_u8 *buffer = NULL;
    t_u16 cmd_len = 0;
    int opt, ret = 0;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_cfg_noa_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if ((argc != 2) && (argc != 4) && (argc != 7)) {
        printf("ERR: Wrong number of arguments!\n");
        print_wifidirect_cfg_noa_usage();
        return;
    }
    if (argc > 2) {
        if (argc == 4) {
            if (strcmp(argv[2], "enable") == 0) {
                printf("ERR: index, count_type, duration and interval must be"
                       " specified if noa is enabled!\n");
                print_wifidirect_cfg_noa_usage();
                return;
            } else if (strcmp(argv[2], "disable")) {
                print_wifidirect_cfg_noa_usage();
                return;
            }
            if (atoi(argv[3]) > WIFIDIRECT_NOA_DESC_MAX) {
                print_wifidirect_cfg_noa_usage();
                return;
            }
        } else {
            if (atoi(argv[3]) > WIFIDIRECT_NOA_DESC_MAX ||
                (is_input_valid(WIFIDIRECT_COUNT_TYPE, 1, &argv[4]) != SUCCESS)
                || (is_input_valid(WIFIDIRECT_DURATION, 1, &argv[5]) != SUCCESS)
                || (is_input_valid(WIFIDIRECT_INTERVAL, 1, &argv[6]) !=
                    SUCCESS)) {
                print_wifidirect_cfg_noa_usage();
                return;
            }
        }
    }
    cmd_len =
        sizeof(wifidirect_params_config) + sizeof(tlvbuf_wifidirect_noa_config);

    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);

    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }

    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);

    cmd_buf = (wifidirect_params_config *) buffer;
    tlv =
        (tlvbuf_wifidirect_noa_config *) (buffer +
                                          sizeof(wifidirect_params_config));

    cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG;
    cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
    cmd_buf->seq_num = 0;
    cmd_buf->result = 0;

    tlv->tag = MRVL_WIFIDIRECT_NOA_TLV_ID;
    tlv->length = sizeof(tlvbuf_wifidirect_noa_config) - MRVL_TLV_HEADER_SIZE;

    if (argc == 2) {
        cmd_buf->action = ACTION_GET;
        cmd_len += (sizeof(tlvbuf_wifidirect_noa_config) - MRVL_TLV_HEADER_SIZE)
            * (WIFIDIRECT_NOA_DESC_MAX - 1);
    } else {
        cmd_buf->action = cpu_to_le16(ACTION_SET);
        if (strcmp(argv[2], "disable")) {
            /* enable case */
            tlv->enable_noa = 1;
            tlv->enable_noa = cpu_to_le16(tlv->enable_noa);
        }
        tlv->noa_index = (t_u8) atoi(argv[3]);

        if (tlv->enable_noa) {
            tlv->count_type = (t_u8) atoi(argv[4]);
            tlv->duration = (t_u32) atoi(argv[5]);
            tlv->duration = cpu_to_le32(tlv->duration);
            tlv->interval = (t_u32) atoi(argv[6]);
            tlv->interval = cpu_to_le32(tlv->interval);
        }
    }
    endian_convert_tlv_header_out(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len, ' ');
#endif
    ret =
        wifidirect_ioctl((t_u8 *) buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER);
    endian_convert_tlv_header_in(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' ');
#endif
    /* Process Response */
    if (ret == SUCCESS) {
        /* Verify response */
        if (cmd_buf->cmd_code !=
            (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | WIFIDIRECTCMD_RESP_CHECK)) {
            printf("ERR:Corrupted response!\n");
            goto done;
        }
        /* Print response */
        if (cmd_buf->result == CMD_SUCCESS) {
            if (argc == 2) {
                if (tlv->length)
                    printf("NoA settings:\n");
                else
                    printf("NoA parameters are not configured.\n");
                if (tlv->length >=
                    sizeof(tlvbuf_wifidirect_noa_config) -
                    MRVL_TLV_HEADER_SIZE) {
                    tlv->enable_noa = le16_to_cpu(tlv->enable_noa);
                    if (tlv->enable_noa) {
                        printf("[%d] NoA is enabled!\n", (int) tlv->noa_index);
                        printf("CountType = %d\n", (int) tlv->count_type);
                        printf("Duration = %dms\n", le32_to_cpu(tlv->duration));
                        printf("Interval = %dms\n", le32_to_cpu(tlv->interval));
                    } else {
                        printf("[%d] NoA is disabled!\n", (int) tlv->noa_index);
                    }
                }
            } else {
                printf("NoA setting successful!\n");
            }
        } else {
            if (argc == 2) {
                printf("ERR:Couldn't get NoA parameters!\n");
            } else {
                printf("ERR:Couldn't set NoA parameters!\n");
            }
        }
    } else {
        printf("ERR:Command sending failed!\n");
    }
  done:
    if (buffer)
        free(buffer);
    return;
}

/**
 *  @brief Show usage information for the wifidirect opp_ps config command
 *
 *  @return         N/A
 */
static void
print_wifidirect_cfg_opp_ps_usage(void)
{
    printf("Usage : wifidirect_cfg_opp_ps <enable|disable> [<CTWindow>]\n");
    printf("For 'set', both enable flag and CTWindow should be provided.\n");
    printf("If no parameter is specified,'get' is performed.\n");
    return;
}

/** 
 *  @brief Set/get wifidirect Opportunistic Power Save
 *
 *  Usage: "Usage : wifidirect_cfg_opp_ps <enable|disable> [<CTWindow>]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         None 
 */
static void
wifidirect_cfg_cmd_opp_ps(int argc, char *argv[])
{
    wifidirect_params_config *cmd_buf = NULL;
    tlvbuf_wifidirect_opp_ps_config *tlv = NULL;
    t_u8 *buffer = NULL;
    t_u16 cmd_len = 0;
    t_u8 opp_ps = 0, ctwindow = 0;
    int opt, ret = 0;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_cfg_opp_ps_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if ((argc < 2) || (argc > 4)) {
        printf("ERR: Wrong number of arguments!\n");
        print_wifidirect_cfg_opp_ps_usage();
        return;
    }
    if (argc == 3) {
        if (strcmp(argv[2], "enable") == 0) {
            printf("ERR: If Opp PS is enabled, CTWindow must be specified!\n");
            print_wifidirect_cfg_opp_ps_usage();
            return;
        } else if (strcmp(argv[2], "disable")) {
            print_wifidirect_cfg_opp_ps_usage();
            return;
        }
    }
    if (argc == 4) {
        if (strcmp(argv[2], "disable") == 0) {
            printf("ERR: Extra parameter %s for disable command.\n", argv[3]);
            return;
        }
        if (is_input_valid(WIFIDIRECT_CTWINDOW, 1, &argv[3]) != SUCCESS) {
            print_wifidirect_cfg_opp_ps_usage();
            return;
        }
    }

    cmd_len =
        sizeof(wifidirect_params_config) +
        sizeof(tlvbuf_wifidirect_opp_ps_config);

    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);

    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }

    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);

    cmd_buf = (wifidirect_params_config *) buffer;
    tlv =
        (tlvbuf_wifidirect_opp_ps_config *) (buffer +
                                             sizeof(wifidirect_params_config));

    cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG;
    cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
    cmd_buf->seq_num = 0;
    cmd_buf->result = 0;

    tlv->tag = MRVL_WIFIDIRECT_OPP_PS_TLV_ID;
    tlv->length =
        sizeof(tlvbuf_wifidirect_opp_ps_config) - MRVL_TLV_HEADER_SIZE;

    if (argc == 2) {
        cmd_buf->action = ACTION_GET;
    } else {
        cmd_buf->action = cpu_to_le16(ACTION_SET);
        if (strcmp(argv[2], "disable"))
            opp_ps = 1;
        if (argc == 4)
            tlv->ctwindow_opp_ps = (t_u8) atoi(argv[3]) | SET_OPP_PS(opp_ps);;
    }
    endian_convert_tlv_header_out(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len, ' ');
#endif
    ret =
        wifidirect_ioctl((t_u8 *) buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER);
    endian_convert_tlv_header_in(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' ');
#endif
    /* Process Response */
    if (ret == SUCCESS) {
        /* Verify response */
        if (cmd_buf->cmd_code !=
            (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | WIFIDIRECTCMD_RESP_CHECK)) {
            printf("ERR:Corrupted response!\n");
            goto done;
        }
        /* Print response */
        if (cmd_buf->result == CMD_SUCCESS) {
            if (argc == 2) {
                opp_ps = GET_OPP_PS(tlv->ctwindow_opp_ps);
                if (opp_ps) {
                    ctwindow = (tlv->ctwindow_opp_ps) & CT_WINDOW_MASK;
                    printf("Opportunistic Power Save enabled!\n");
                    printf("CTWindow  = %d\n", ctwindow);
                } else {
                    printf("Opportunistic Power Save disabled!\n");
                }
            } else {
                printf("Opportunistic power save setting successful!\n");
            }
        } else {
            if (argc == 2) {
                printf
                    ("ERR:Couldn't get Opportunistic power save and CTWindow!\n");
            } else {
                printf
                    ("ERR:Couldn't set Opportunistic power save and CTWindow!\n");
            }
        }
    } else {
        printf("ERR:Command sending failed!\n");
    }
  done:
    if (buffer)
        free(buffer);
    return;
}

/**
 *  @brief Show usage information for the wifidirect capability config command
 *
 *  @return         N/A
 */
static void
print_wifidirect_cfg_capability_usage(void)
{
    printf
        ("Usage : wifidirect_capability [<DeviceCapability> <GroupCapability>]\n");
    printf
        ("For 'set' both DeviceCapability and GroupCapability should be provided.\n");
    printf("If no parameter is specified,'get' is performed.\n");
    return;
}

/** 
 *  @brief Set/get wifidirect Capability
 *  
 *  Usage: "Usage : wifidirect_cfg_capability [<DeviceCapability> <GroupCapability>]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         None 
 */
static void
wifidirect_cfg_cmd_capability(int argc, char *argv[])
{
    wifidirect_params_config *cmd_buf = NULL;
    tlvbuf_wifidirect_capability_config *tlv = NULL;
    t_u8 *buffer = NULL;
    t_u16 cmd_len = 0;
    int opt, ret = 0;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_cfg_capability_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if ((argc < 2) || (argc > 4) || (argc == 3)) {
        printf("ERR: Wrong number of arguments!\n");
        print_wifidirect_cfg_capability_usage();
        return;
    }
    if (argc == 4) {
        if ((is_input_valid(WIFIDIRECT_DEVICECAPABILITY, 1, &argv[2]) !=
             SUCCESS) ||
            (is_input_valid(WIFIDIRECT_GROUPCAPABILITY, 1, &argv[3]) !=
             SUCCESS)) {
            print_wifidirect_cfg_capability_usage();
            return;
        }
    }
    cmd_len =
        sizeof(wifidirect_params_config) +
        sizeof(tlvbuf_wifidirect_capability_config);

    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);

    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }

    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);

    cmd_buf = (wifidirect_params_config *) buffer;
    tlv =
        (tlvbuf_wifidirect_capability_config *) (buffer +
                                                 sizeof
                                                 (wifidirect_params_config));

    cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG;
    cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
    cmd_buf->seq_num = 0;
    cmd_buf->result = 0;

    tlv->tag = MRVL_WIFIDIRECT_CAPABILITY_TLV_ID;
    tlv->length =
        sizeof(tlvbuf_wifidirect_capability_config) - MRVL_TLV_HEADER_SIZE;

    if (argc == 2) {
        cmd_buf->action = ACTION_GET;
    } else {
        cmd_buf->action = cpu_to_le16(ACTION_SET);
        tlv->dev_capability = (t_u8) atoi(argv[2]);
        tlv->group_capability = (t_u8) atoi(argv[3]);
    }
    endian_convert_tlv_header_out(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len, ' ');
#endif
    ret =
        wifidirect_ioctl((t_u8 *) buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER);
    endian_convert_tlv_header_in(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' ');
#endif
    /* Process Response */
    if (ret == SUCCESS) {
        /* Verify response */
        if (cmd_buf->cmd_code !=
            (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | WIFIDIRECTCMD_RESP_CHECK)) {
            printf("ERR:Corrupted response!\n");
            goto done;
        }
        /* Print response */
        if (cmd_buf->result == CMD_SUCCESS) {
            if (argc == 2) {
                printf("Device Capability = %d\n", (int) tlv->dev_capability);
                printf("Group Capability = %d\n", (int) tlv->group_capability);
            } else {
                printf("Capability setting successful!\n");
            }
        } else {
            if (argc == 2) {
                printf("ERR:Couldn't get Capability info!\n");
            } else {
                printf("ERR:Couldn't set Capability!\n");
            }
        }
    } else {
        printf("ERR:Command sending failed!\n");
    }
  done:
    if (buffer)
        free(buffer);
    return;
}

/**
 *  @brief Show usage information for the wifidirect_cfg_persistent_group_record command
 *
 *  $return         N/A
 */
static void
print_wifidirect_peristent_group_usage(void)
{
    printf("\nUsage : wifidirect_cfg_persistent_group_record [index] \
            <role> <bssid> <groupdevid> <ssid> <psk>> \
            [<peermac1> <peermac2> ]\n");
    printf("\nIssue set or get request using appropriate parameters.\n");
    return;
}

/** 
 *  @brief Creates a wifidirect_persistent group record request and
 *         sends to the driver
 *
 *  Usage: "Usage : wifidirect_cfg_cmd_persistent_group_record [index] < 
 *                  <role> <bssid> <groupdevid> <ssid> <psk>>
 *                  [<peermac1> <peermac2> ]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         SUCCESS or FAILURE
 **/
static void
wifidirect_cfg_cmd_persistent_group_record(int argc, char *argv[])
{
    wifidirect_params_config *cmd_buf = NULL;
    tlvbuf_wifidirect_persistent_group *tlv = NULL;
    t_u8 index = 0, role = 0, var_len = 0, psk_len = 0;
    t_u8 *buffer = NULL;
    int pi;
    t_u16 cmd_len = 0, buf_len = 0;
    int opt, ret;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_peristent_group_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if (argc != 2 && argc != 3 && argc != 8 && argc != 9 && argc != 10) {
        printf("ERR:wrong number of arguments.\n");
        print_wifidirect_peristent_group_usage();
        return;
    }
    /* error checks */
    if (argc > 2) {
        index = atoi(argv[2]);
        if (index >= WIFIDIRECT_PERSISTENT_GROUP_MAX) {
            printf("ERR:wrong index. Value values are [0-3]\n");
            return;
        }
    }
    if (argc > 3) {
        role = atoi(argv[3]);
        if ((role != 1) && (role != 2)) {
            printf
                ("ERR:Incorrect Role. Use 2 for client, 1 for group owner.\n");
            return;
        }
        if (role == 1 && argc == 8) {
            printf
                ("ERR:Insufficient arguments. Please provide peer mac address(es) for group owner.\n");
            return;
        }
    }

    cmd_len = sizeof(wifidirect_params_config);
    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);
    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }
    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
    cmd_buf = (wifidirect_params_config *) buffer;
    cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG;
    cmd_buf->seq_num = 0;
    cmd_buf->result = 0;
    tlv =
        (tlvbuf_wifidirect_persistent_group *) (buffer +
                                                sizeof
                                                (wifidirect_params_config));

    tlv->tag = MRVL_WIFIDIRECT_PERSISTENT_GROUP_TLV_ID;

    /* parsing commands based on arguments */
    switch (argc) {
    case 2:
        cmd_buf->action = ACTION_GET;
        tlv->length = 0;
        cmd_len += MRVL_TLV_HEADER_SIZE + tlv->length;
        cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
        buf_len = MRVDRV_SIZE_OF_CMD_BUFFER;
        break;

    case 3:
        cmd_buf->action = ACTION_GET;
        tlv->rec_index = index;
        tlv->length = sizeof(index);
        cmd_len += MRVL_TLV_HEADER_SIZE + tlv->length;
        cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
        buf_len = MRVDRV_SIZE_OF_CMD_BUFFER;
        break;

    default:
        cmd_buf->action = cpu_to_le16(ACTION_SET);
        tlv->rec_index = index;
        tlv->dev_role = role;
        if ((ret = mac2raw(argv[4], tlv->group_bssid)) != SUCCESS) {
            printf("ERR:Invalid MAC address %s\n", argv[4]);
            goto done;
        }
        if ((ret = mac2raw(argv[5], tlv->dev_mac_address)) != SUCCESS) {
            printf("ERR:Invalid MAC address %s\n", argv[5]);
            goto done;
        }

        /* ssid */
        tlv->group_ssid_len = strlen(argv[6]);
        var_len += tlv->group_ssid_len;
        memcpy(tlv->group_ssid, argv[6], tlv->group_ssid_len);

        /* adjust pointer from here */
        /* psk */
        if (!strncasecmp("0x", argv[7], 2)) {
            argv[7] += 2;
            if (strlen(argv[7]) / 2 != WIFIDIRECT_PSK_LEN_MAX) {
                printf("ERR:Incorrect PSK length %d. It should be %d.\n",
                       (t_u32) strlen(argv[7]) / 2, WIFIDIRECT_PSK_LEN_MAX);
                goto done;
            }
            string2raw(argv[7], tlv->psk + var_len);
            *(&tlv->psk_len + var_len) = WIFIDIRECT_PSK_LEN_MAX;
            var_len += WIFIDIRECT_PSK_LEN_MAX;
        } else {
            /* ascii */
            psk_len = strlen(argv[7]);
            if (psk_len < WIFIDIRECT_PASSPHRASE_LEN_MIN ||
                psk_len >= WIFIDIRECT_PSK_LEN_MAX) {
                printf
                    ("ERR:Incorrect passphrase length %d. Valid range is [8-63]\n",
                     psk_len);
                goto done;
            }
            memcpy(tlv->psk + var_len, argv[7], psk_len);
            *(&tlv->psk_len + var_len) = psk_len;
            var_len += psk_len;
        }

        tlv->length =
            sizeof(tlvbuf_wifidirect_persistent_group) - MRVL_TLV_HEADER_SIZE +
            var_len;
        *(&tlv->num_peers + var_len) = 0;

        if (argc == 9 || argc == 10) {
            if ((ret = mac2raw(argv[8], tlv->peer_mac_addrs[0] + var_len))
                != SUCCESS) {
                printf("ERR:Invalid MAC address %s\n", argv[8]);
                goto done;
            }
            *(&tlv->num_peers + var_len) = 1;
        }
        if (argc == 10) {
            if ((ret = mac2raw(argv[9], tlv->peer_mac_addrs[1] + var_len))
                != SUCCESS) {
                printf("ERR:Invalid MAC address %s\n", argv[8]);
                goto done;
            }
            *(&tlv->num_peers + var_len) = 2;
        }

        tlv->length += *(&tlv->num_peers + var_len) * ETH_ALEN;
        cmd_len += MRVL_TLV_HEADER_SIZE + tlv->length;
        buf_len = cmd_len;
        cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
        break;
    }
#ifdef DEBUG
    hexdump(buffer, cmd_len, ' ');
#endif
    endian_convert_tlv_header_out(tlv);

    /* Send collective command */
    wifidirect_ioctl((t_u8 *) buffer, &cmd_len, buf_len);

    endian_convert_tlv_header_in(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len, ' ');
#endif

    if (argc == 2 || argc == 3) {
        if (tlv->length > 0)
            printf("Persistent group information =>\n");
        else
            printf("Persistent group information is empty.\n");
        buf_len = tlv->length;
        while (buf_len >
               (sizeof(tlvbuf_wifidirect_persistent_group) - 2 * ETH_ALEN)) {
            printf("\n\t Index = [%d]\n", tlv->rec_index);
            if (tlv->dev_role == 1)
                printf("\t Role  = Group owner\n");
            else
                printf("\t Role  = Client\n");
            printf("\t GroupBssId - ");
            print_mac(tlv->group_bssid);
            printf("\n\t DeviceId - ");
            print_mac(tlv->dev_mac_address);
            printf("\n\t SSID = ");
            for (index = 0; index < tlv->group_ssid_len; index++)
                printf("%c", tlv->group_ssid[index]);
            var_len = tlv->group_ssid_len;
            printf("\n\t PSK = ");
            for (index = 0; index < *(&tlv->psk_len + var_len); index++) {
                if (index == 16)
                    printf("\n\t       ");
                printf("%02x ", *(&tlv->psk[index] + var_len));
            }
            var_len += *(&tlv->psk_len + var_len);
            if (tlv->dev_role == 1) {
                for (pi = 0; pi < *(&tlv->num_peers + var_len); pi++) {
                    printf("\n\t Peer Mac address(%d) = ", pi);
                    print_mac(tlv->peer_mac_addrs[pi] + var_len);
                }
                var_len += (*(&tlv->num_peers + var_len) * ETH_ALEN);
            }
            if (argc == 2)
                printf("\n\t -----------------------------------------");
            if (tlv->dev_role == 1) {
                buf_len -= sizeof(tlvbuf_wifidirect_persistent_group) -
                    MRVL_TLV_HEADER_SIZE + var_len;
                tlv = (tlvbuf_wifidirect_persistent_group *) (((t_u8 *) (tlv)) +
                                                              (sizeof
                                                               (tlvbuf_wifidirect_persistent_group)
                                                               -
                                                               MRVL_TLV_HEADER_SIZE
                                                               + var_len));
            } else {
                /* num_peer field willnt be present */
                buf_len -= sizeof(tlvbuf_wifidirect_persistent_group) -
                    MRVL_TLV_HEADER_SIZE - sizeof(t_u8) + var_len;
                tlv = (tlvbuf_wifidirect_persistent_group *) (((t_u8 *) (tlv)) +
                                                              (sizeof
                                                               (tlvbuf_wifidirect_persistent_group)
                                                               -
                                                               MRVL_TLV_HEADER_SIZE
                                                               - sizeof(t_u8) +
                                                               var_len));
            }
        }
        printf("\n");
    } else {
        printf("Setting persistent group information successful!\n");
    }
  done:
    if (buffer)
        free(buffer);
    return;
}

/**
 *  @brief Show usage information for the wifidirect_cfg_persistent_group_invoke command
 *
 *  $return         N/A
 */
static void
print_wifidirect_peristent_group_invoke_usage(void)
{
    printf
        ("\nUsage : wifidirect_cfg_persistent_group_invoke [index] | <cancel>\n");
    return;
}

/** 
 *  @brief Creates a wifidirect_persistent group Invoke request and
 *         sends to the driver
 *
 *  Usage: "Usage : wifidirect_cfg_cmd_persistent_group_invoke [index] | <cancel>"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         SUCCESS or FAILURE
 **/
static void
wifidirect_cfg_cmd_persistent_group_invoke(int argc, char *argv[])
{
    wifidirect_params_config *cmd_buf = NULL;
    tlvbuf_wifidirect_persistent_group *tlv = NULL;
    t_u8 index;
    t_u8 *buffer = NULL;
    t_u16 cmd_len = 0;
    int opt;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_peristent_group_invoke_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if (argc != 3) {
        printf("ERR:wrong number of arguments.\n");
        print_wifidirect_peristent_group_invoke_usage();
        return;
    }

    cmd_len = sizeof(wifidirect_params_config);
    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);
    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }
    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
    cmd_buf = (wifidirect_params_config *) buffer;
    cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG;
    cmd_buf->seq_num = 0;
    cmd_buf->result = 0;
    cmd_buf->action = cpu_to_le16(ACTION_SET);
    tlv =
        (tlvbuf_wifidirect_persistent_group *) (buffer +
                                                sizeof
                                                (wifidirect_params_config));

    tlv->tag = MRVL_WIFIDIRECT_PERSISTENT_GROUP_TLV_ID;
    tlv->length = sizeof(index);

    index = atoi(argv[2]);
    if (index >= WIFIDIRECT_PERSISTENT_GROUP_MAX) {
        printf("ERR:wrong index. Value values are [0-3]\n");
        goto done;
    }
    if (!isdigit(argv[2][0])) {
        if (strcmp(argv[2], "cancel")) {
            printf("ERR:Incorrect input. Use index [0-3] or \"cancel\" \n");
            goto done;
        } else
            index = WIFIDIRECT_PERSISTENT_RECORD_CANCEL;
    }
    tlv->rec_index = index;

    cmd_len += MRVL_TLV_HEADER_SIZE + tlv->length;
    cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
#ifdef DEBUG
    hexdump(buffer, cmd_len, ' ');
#endif
    endian_convert_tlv_header_out(tlv);

    /* Send collective command */
    wifidirect_ioctl((t_u8 *) buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER);

#ifdef DEBUG
    hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' ');
#endif

    printf("Persistent group %s successful!\n",
           (index ==
            WIFIDIRECT_PERSISTENT_RECORD_CANCEL) ? "cancel" : "invoke");
  done:
    if (buffer)
        free(buffer);
    return;
}

/**
 *  @brief Show usage information for the wifidirect presence request parameters command
 *
 *  @return         N/A
 */
static void
print_wifidirect_cfg_presence_req_params_usage(void)
{
    printf
        ("Usage : wifidirect_cfg_presence_req_params [<type> <duration> <interval>]\n");
    printf("      : Type 1: preferred values, 2: acceptable values.\n");
    printf("If presence request parameters are provided, "
           " 'set' is performed otherwise 'get' is performed.\n");
    return;
}

/** 
 *  @brief Set/get wifidirect presence request parameters
 *
 *  Usage: "Usage : wifidirect_cfg_presence_req_params [<type> <duration> <interval>]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         None 
 */
static void
wifidirect_cfg_cmd_presence_req_params(int argc, char *argv[])
{
    wifidirect_params_config *cmd_buf = NULL;
    tlvbuf_wifidirect_presence_req_params *tlv = NULL;
    t_u8 *buffer = NULL;
    t_u16 cmd_len = 0;
    int opt, ret = 0;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_cfg_presence_req_params_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if (argc < 2) {
        printf("ERR: Wrong number of arguments!\n");
        print_wifidirect_cfg_presence_req_params_usage();
        return;
    } else if ((argc > 2) && ((argc != 5)
                              ||
                              (is_input_valid
                               (WIFIDIRECT_PRESENCE_REQ_TYPE, 1,
                                &argv[2]) != SUCCESS)
                              ||
                              (is_input_valid(WIFIDIRECT_DURATION, 1, &argv[3])
                               != SUCCESS)
                              ||
                              (is_input_valid(WIFIDIRECT_INTERVAL, 1, &argv[4])
                               != SUCCESS))) {
        print_wifidirect_cfg_presence_req_params_usage();
        return;
    }
    cmd_len =
        sizeof(wifidirect_params_config) +
        sizeof(tlvbuf_wifidirect_presence_req_params);

    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);

    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }

    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);

    cmd_buf = (wifidirect_params_config *) buffer;
    tlv =
        (tlvbuf_wifidirect_presence_req_params *) (buffer +
                                                   sizeof
                                                   (wifidirect_params_config));

    cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG;
    cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
    cmd_buf->seq_num = 0;
    cmd_buf->result = 0;

    tlv->tag = MRVL_WIFIDIRECT_PRESENCE_REQ_PARAMS_TLV_ID;
    tlv->length =
        sizeof(tlvbuf_wifidirect_presence_req_params) - MRVL_TLV_HEADER_SIZE;

    if (argc == 2) {
        cmd_buf->action = ACTION_GET;
    } else {
        cmd_buf->action = cpu_to_le16(ACTION_SET);
        tlv->presence_req_type = (t_u8) atoi(argv[2]);
        tlv->duration = (t_u32) atoi(argv[3]);
        tlv->duration = cpu_to_le32(tlv->duration);
        tlv->interval = (t_u32) atoi(argv[4]);
        tlv->interval = cpu_to_le32(tlv->interval);
    }
    endian_convert_tlv_header_out(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len, ' ');
#endif
    ret =
        wifidirect_ioctl((t_u8 *) buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER);
    endian_convert_tlv_header_in(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' ');
#endif
    /* Process Response */
    if (ret == SUCCESS) {
        /* Verify response */
        if (cmd_buf->cmd_code !=
            (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | WIFIDIRECTCMD_RESP_CHECK)) {
            printf("ERR:Corrupted response!\n");
            goto done;
        }
        /* Print response */
        if (cmd_buf->result == CMD_SUCCESS) {
            if (argc == 2) {
                printf("Presence request type = %d\n",
                       (int) tlv->presence_req_type);
                printf("Duration of NoA descriptor = %d\n",
                       le32_to_cpu(tlv->duration));
                printf("Interval of NoA descriptor = %d\n",
                       le32_to_cpu(tlv->interval));
            } else {
                printf("Presence request parameters setting successful!\n");
            }
        } else {
            if (argc == 2) {
                printf("ERR:Couldn't get Presence request parameters!\n");
            } else {
                printf("ERR:Couldn't set Presence request parameters!\n");
            }
        }
    } else {
        printf("ERR:Command sending failed!\n");
    }
  done:
    if (buffer)
        free(buffer);
    return;
}

/**
 *  @brief Show usage information for the wifidirect extended listen timing parameters command
 *
 *  @return         N/A
 */
static void
print_wifidirect_cfg_ext_listen_time_usage(void)
{
    printf("Usage : wifidirect_cfg_ext_listen_time [<duration> <interval>]\n");
    printf("If extended listen timing parameters are provided, "
           "'set' is performed otherwise 'get' is performed.\n");
    return;
}

/** 
 *  @brief Set/get wifidirect extended listen time parameters
 *
 *  Usage: "Usage : wifidirect_cfg_ext_listen_time [<duration> <interval>]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         None 
 */
static void
wifidirect_cfg_cmd_ext_listen_time(int argc, char *argv[])
{
    wifidirect_params_config *cmd_buf = NULL;
    tlvbuf_wifidirect_mrvl_ext_listen_time *tlv = NULL;
    t_u8 *buffer = NULL;
    t_u16 cmd_len = 0;
    int opt, ret = 0;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_cfg_ext_listen_time_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if (argc < 2) {
        printf("ERR: Wrong number of arguments!\n");
        print_wifidirect_cfg_ext_listen_time_usage();
        return;
    } else if ((argc > 2) && ((argc != 4)
                              ||
                              (is_input_valid
                               (WIFIDIRECT_ATTR_EXTENDED_TIME, 1,
                                &argv[2]) != SUCCESS)
                              ||
                              (is_input_valid
                               (WIFIDIRECT_ATTR_EXTENDED_TIME, 1,
                                &argv[3]) != SUCCESS))) {
        print_wifidirect_cfg_ext_listen_time_usage();
        return;
    }
    cmd_len =
        sizeof(wifidirect_params_config) +
        sizeof(tlvbuf_wifidirect_mrvl_ext_listen_time);

    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);

    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }

    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);

    cmd_buf = (wifidirect_params_config *) buffer;
    tlv =
        (tlvbuf_wifidirect_mrvl_ext_listen_time *) (buffer +
                                                    sizeof
                                                    (wifidirect_params_config));

    cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG;
    cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
    cmd_buf->seq_num = 0;
    cmd_buf->result = 0;

    tlv->tag = MRVL_WIFIDIRECT_EXTENDED_LISTEN_TIME_TLV_ID;
    tlv->length =
        sizeof(tlvbuf_wifidirect_mrvl_ext_listen_time) - MRVL_TLV_HEADER_SIZE;
    if (argc == 2) {
        cmd_buf->action = ACTION_GET;
    } else {
        cmd_buf->action = cpu_to_le16(ACTION_SET);
        tlv->duration = cpu_to_le16((t_u16) atoi(argv[2]));
        tlv->interval = cpu_to_le16((t_u16) atoi(argv[3]));
    }
    endian_convert_tlv_header_out(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len, ' ');
#endif
    ret =
        wifidirect_ioctl((t_u8 *) buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER);
    endian_convert_tlv_header_in(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' ');
#endif
    /* Process Response */
    if (ret == SUCCESS) {
        /* Verify response */
        if (cmd_buf->cmd_code !=
            (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | WIFIDIRECTCMD_RESP_CHECK)) {
            printf("ERR:Corrupted response!\n");
            goto done;
        }
        /* Print response */
        if (cmd_buf->result == CMD_SUCCESS) {
            if (argc == 2) {
                printf("Availability Period = %d\n",
                       le16_to_cpu(tlv->duration));
                printf("Availability Interval = %d\n",
                       le16_to_cpu(tlv->interval));
            } else {
                printf
                    ("Extended listen timing parameters setting successful!\n");
            }
        } else {
            if (argc == 2)
                printf("ERR:Couldn't get Extended listen time!\n");
            else
                printf("ERR:Couldn't set Extended listen time!\n");
        }
    } else {
        printf("ERR:Command sending failed!\n");
    }
  done:
    if (buffer)
        free(buffer);
    return;
}

/**
 *  @brief Show usage information for the wifidirect provisioing parameters command
 *
 *  @return         N/A
 */
static void
print_wifidirect_cfg_provisioning_params_usage(void)
{
    printf
        ("Usage : wifidirect_cfg_provisioning_params [<action> <configMethod> <devPassword>]\n");
    printf("      : Action 1: Request parameters 2: Response parameters.\n");
    printf("If provisioning protocol parameters are provided, "
           "'set' is performed otherwise 'get' is performed.\n");
    return;
}

/** 
 *  @brief Set/get wifidirect provisioning protocol related parameters
 *
 *  Usage: "Usage : wifidirect_cfg_provisioning_params [<action> <configMethod>
 *                  <devPassword>]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         None 
 */
static void
wifidirect_cfg_cmd_provisioning_params(int argc, char *argv[])
{
    wifidirect_params_config *cmd_buf = NULL;
    tlvbuf_wifidirect_provisioning_params *tlv = NULL;
    t_u8 *buffer = NULL;
    t_u16 cmd_len = 0;
    int opt, ret = 0;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_cfg_provisioning_params_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if (argc < 2) {
        printf("ERR: Wrong number of arguments!\n");
        print_wifidirect_cfg_provisioning_params_usage();
        return;
    } else if ((argc > 2) && (argc != 5)) {
        print_wifidirect_cfg_provisioning_params_usage();
        return;
    }
    cmd_len =
        sizeof(wifidirect_params_config) +
        sizeof(tlvbuf_wifidirect_provisioning_params);

    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);

    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }

    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);

    cmd_buf = (wifidirect_params_config *) buffer;
    tlv =
        (tlvbuf_wifidirect_provisioning_params *) (buffer +
                                                   sizeof
                                                   (wifidirect_params_config));

    cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG;
    cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
    cmd_buf->seq_num = 0;
    cmd_buf->result = 0;

    tlv->tag = MRVL_WIFIDIRECT_PROVISIONING_PARAMS_TLV_ID;
    tlv->length =
        sizeof(tlvbuf_wifidirect_provisioning_params) - MRVL_TLV_HEADER_SIZE;
    if (argc == 2) {
        cmd_buf->action = ACTION_GET;
    } else {
        cmd_buf->action = cpu_to_le16(ACTION_SET);
        tlv->action = cpu_to_le16((t_u16) A2HEXDECIMAL(argv[2]));
        tlv->config_methods = cpu_to_le16((t_u16) A2HEXDECIMAL(argv[3]));
        tlv->dev_password = cpu_to_le16((t_u16) A2HEXDECIMAL(argv[4]));
    }
    endian_convert_tlv_header_out(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len, ' ');
#endif
    ret =
        wifidirect_ioctl((t_u8 *) buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER);
    endian_convert_tlv_header_in(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' ');
#endif
    /* Process Response */
    if (ret == SUCCESS) {
        /* Verify response */
        if (cmd_buf->cmd_code !=
            (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | WIFIDIRECTCMD_RESP_CHECK)) {
            printf("ERR:Corrupted response!\n");
            goto done;
        }
        /* Print response */
        if (cmd_buf->result == CMD_SUCCESS) {
            if (argc == 2) {
                printf("Action = %s %s\n", (le16_to_cpu(tlv->action)) == 1 ?
                       "Request" : "Response", "parameters");
                printf("Config Methods = %02X\n",
                       le16_to_cpu(tlv->config_methods));
                printf("Device Password ID = %02X\n",
                       le16_to_cpu(tlv->dev_password));
            } else {
                printf
                    ("Provisioning protocol parameters setting successful!\n");
            }
        } else {
            if (argc == 2)
                printf("ERR:Couldn't get provisioing parameters!\n");
            else
                printf("ERR:Couldn't set provisioing parameters!\n");
        }
    } else {
        printf("ERR:Command sending failed!\n");
    }
  done:
    if (buffer)
        free(buffer);
    return;
}

/**
 *  @brief Show usage information for the wifidirect WPS params command
 *
 *  @return         N/A
 */
static void
print_wifidirect_cfg_wps_params_usage(void)
{
    printf("\nUsage : wifidirect_cfg_wps_params [pin/pbc/none]");
    printf("\nIf pin/pbc/none is provided, 'set' is performed"
           " otherwise 'get' is performed.\n");
    return;
}

/** 
 *  @brief Set/get wifidirect WPS parametters 
 *
 *  Usage: "Usage : wifidirect_cfg_wps_params [pin/pbc/none]"
 *
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         None 
 */
static void
wifidirect_cfg_cmd_wps_params(int argc, char *argv[])
{
    wifidirect_params_config *cmd_buf = NULL;
    tlvbuf_wifidirect_wps_params *tlv = NULL;
    t_u8 *buffer = NULL;
    t_u16 cmd_len = 0;
    int opt, ret = 0, param = 0;

    while ((opt = getopt_long(argc, argv, "+", cmd_options, NULL)) != -1) {
        switch (opt) {
        default:
            print_wifidirect_cfg_wps_params_usage();
            return;
        }
    }
    argc -= optind;
    argv += optind;

    /* Check arguments */
    if ((argc < 2) || (argc > 3)) {
        printf("ERR:Wrong number of arguments!\n");
        print_wifidirect_cfg_wps_params_usage();
        return;
    }

    cmd_len =
        sizeof(wifidirect_params_config) + sizeof(tlvbuf_wifidirect_wps_params);

    buffer = (t_u8 *) malloc(MRVDRV_SIZE_OF_CMD_BUFFER);

    if (!buffer) {
        printf("ERR:Cannot allocate memory!\n");
        goto done;
    }

    memset(buffer, 0, MRVDRV_SIZE_OF_CMD_BUFFER);

    cmd_buf = (wifidirect_params_config *) buffer;
    tlv =
        (tlvbuf_wifidirect_wps_params *) (buffer +
                                          sizeof(wifidirect_params_config));

    cmd_buf->cmd_code = HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG;
    cmd_buf->size = cmd_len - BUF_HEADER_SIZE;
    cmd_buf->seq_num = 0;
    cmd_buf->result = 0;

    tlv->tag = MRVL_WIFIDIRECT_WPS_PARAMS_TLV_ID;
    tlv->length = sizeof(tlvbuf_wifidirect_wps_params) - MRVL_TLV_HEADER_SIZE;

    if (argc == 2) {
        cmd_buf->action = ACTION_GET;
    } else {
        if (strncmp(argv[2], "pin", 3) == 0)
            param = 1;
        else if (strncmp(argv[2], "pbc", 3) == 0)
            param = 2;
        else if (strncmp(argv[2], "none", 4)) {
            printf("Invalid input, should be pin/pbc or none.\n");
            goto done;
        }
        cmd_buf->action = cpu_to_le16(ACTION_SET);
        tlv->action = cpu_to_le16(param);
    }
    endian_convert_tlv_header_out(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len, ' ');
#endif
    ret =
        wifidirect_ioctl((t_u8 *) buffer, &cmd_len, MRVDRV_SIZE_OF_CMD_BUFFER);
    endian_convert_tlv_header_in(tlv);
#ifdef DEBUG
    hexdump(buffer, cmd_len + BUF_HEADER_SIZE, ' ');
#endif
    /* Process Response */
    if (ret == SUCCESS) {
        /* Verify response */
        if (cmd_buf->cmd_code !=
            (HostCmd_CMD_WIFIDIRECT_PARAMS_CONFIG | WIFIDIRECTCMD_RESP_CHECK)) {
            printf("ERR:Corrupted response!\n");
            goto done;
        }
        /* Print response */
        if (cmd_buf->result == CMD_SUCCESS) {
            if (argc == 2) {
                printf("WPS password parameter =>");
                switch (le16_to_cpu(tlv->action)) {
                case 1:
                    printf("Pin\n");
                    break;
                case 2:
                    printf("PBC\n");
                    break;
                default:
                    printf("None\n");
                    break;
                }
            } else {
                printf("WPS parameter setting successful!\n");
            }
        } else {
            if (argc == 2) {
                printf("ERR:Couldn't get WPS parameters !\n");
            } else {
                printf("ERR:Couldn't set WPS parameters !\n");
            }
        }
    } else {
        printf("ERR:Command sending failed!\n");
    }
  done:
    if (buffer)
        free(buffer);
    return;
}

/** 
 *  @brief Checkes a particular input for validatation.
 *
 *  @param cmd      Type of input
 *  @param argc     Number of arguments
 *  @param argv     Pointer to the arguments
 *  @return         SUCCESS or FAILURE
 */
int
is_input_valid(valid_inputs cmd, int argc, char *argv[])
{
    int i;
    int ret = SUCCESS;
    char country[6] = { ' ', ' ', 0, 0, 0, 0 };
    char wifidirect_dev_name[34];
    if (argc == 0)
        return FAILURE;
    switch (cmd) {
    case WIFIDIRECT_MINDISCOVERYINT:
        if (argc != 1) {
            printf
                ("ERR:Incorrect number of arguments for MinDiscoveryInterval\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) >= (1 << 16))) {
                printf("ERR:MinDiscoveryInterval must be 2 bytes\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_MAXDISCOVERYINT:
        if (argc != 1) {
            printf
                ("ERR:Incorrect number of arguments for MaxDiscoveryInterval\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) >= (1 << 16))) {
                printf("ERR:MaxDiscoveryInterval must be 2 bytes\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_DEVICECAPABILITY:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for DeviceCapability\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) > MAX_DEV_CAPABILITY)
                || (atoi(argv[0]) < 0)) {
                printf("ERR:DeviceCapability must be in the range [0:%d]\n",
                       MAX_DEV_CAPABILITY);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_GROUPCAPABILITY:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for GroupCapability\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) > MAX_GRP_CAPABILITY)
                || (atoi(argv[0]) < 0)) {
                printf("ERR:GroupCapability must be in the range [0:%d]\n",
                       MAX_GRP_CAPABILITY);
                ret = FAILURE;
            }
        }
        break;
    case CHANNEL:
        if ((argc != 1) && (argc != 2)) {
            printf("ERR: Incorrect arguments for channel.\n");
            ret = FAILURE;
        } else {
            if (argc == 2) {
                if ((ISDIGIT(argv[1]) == 0) || (atoi(argv[1]) < 0) ||
                    (atoi(argv[1]) > 1)) {
                    printf("ERR: MODE must be either 0 or 1\n");
                    ret = FAILURE;
                }
                if ((atoi(argv[1]) == 1) && (atoi(argv[0]) != 0)) {
                    printf("ERR: Channel must be 0 for ACS; MODE = 1.\n");
                    ret = FAILURE;
                }
            }
            if ((argc == 1) || (atoi(argv[1]) == 0)) {
                if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 1) ||
                    (atoi(argv[0]) > MAX_CHANNELS)) {
                    printf
                        ("ERR: Channel must be in the range of 1 to %d, configured - %d\n",
                         MAX_CHANNELS, atoi(argv[0]));
                    ret = FAILURE;
                }
            }
        }
        break;
    case SCANCHANNELS:
        if (argc > MAX_CHANNELS) {
            printf("ERR: Invalid List of Channels\n");
            ret = FAILURE;
        } else {
            for (i = 0; i < argc; i++) {
                if ((ISDIGIT(argv[i]) == 0) || (atoi(argv[i]) < 1) ||
                    (atoi(argv[i]) > MAX_CHANNELS)) {
                    printf
                        ("ERR: Channel must be in the range of 1 to %d, configured - %d\n",
                         MAX_CHANNELS, atoi(argv[i]));
                    ret = FAILURE;
                    break;
                }
            }
            if ((ret != FAILURE) && (has_dup_channel(argc, argv) != SUCCESS)) {
                printf("ERR: Duplicate channel values entered\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_INTENT:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for intent\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) > MAX_INTENT) ||
                (atoi(argv[0]) < 0)) {
                printf("ERR:Intent must be in the range [0:%d]\n", MAX_INTENT);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_MANAGEABILITY:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for manageability\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) ||
                (atoi(argv[0]) > 1)) {
                printf("ERR:Manageability must be either 0 or 1\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_GROUP_WIFIDIRECT_DEVICE_NAME:
        /* 2 extra characters for quotes around device name */
        if ((strlen(argv[0]) > 34)) {
            printf
                ("ERR:WIFIDIRECT Device name string length must not be more than 32\n");
            ret = FAILURE;
        } else {
            strncpy(wifidirect_dev_name, argv[0],
                    sizeof(wifidirect_dev_name) - 1);
            if ((wifidirect_dev_name[0] != '"') ||
                (wifidirect_dev_name[strlen(wifidirect_dev_name) - 1] != '"')) {
                printf
                    ("ERR:WIFIDIRECT Device name must be within double quotes!\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_COUNTRY:
        /* 2 extra characters for quotes around country */
        if ((strlen(argv[0]) > 5) || (strlen(argv[0]) < 4)) {
            printf("ERR:Country string must have length 2 or 3\n");
            ret = FAILURE;
        } else {
            strncpy(country, argv[0], sizeof(country) - 1);
            if ((country[0] != '"') || (country[strlen(country) - 1] != '"')) {
                printf("ERR:country code must be within double quotes!\n");
                ret = FAILURE;
            } else {
                for (i = 1; i < strlen(country) - 2; i++) {
                    if ((toupper(country[i]) < 'A') ||
                        (toupper(country[i]) > 'Z')) {
                        printf("ERR:Invalid Country Code\n");
                        ret = FAILURE;
                    }
                }
            }
        }
        break;
    case WIFIDIRECT_NO_OF_CHANNELS:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for num of channels\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) > MAX_CHANNELS)) {
                printf("ERR:Number of channels should be less than %d\n",
                       MAX_CHANNELS);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_NOA_INDEX:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for NoA Index\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < MIN_NOA_INDEX) ||
                (atoi(argv[0]) > MAX_NOA_INDEX)) {
                printf("ERR:NoA index should be in the range [%d:%d]\n",
                       MIN_NOA_INDEX, MAX_NOA_INDEX);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_OPP_PS:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for Opp PS\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || ((atoi(argv[0]) != 0) &&
                                            (atoi(argv[0]) != 1))) {
                printf("ERR:Opp PS must be either 0 or 1\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_CTWINDOW:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for CTWindow\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) > MAX_CTWINDOW) ||
                (atoi(argv[0]) < MIN_CTWINDOW)) {
                printf("ERR:CT Window must be in the range [%d:%d]\n",
                       MIN_CTWINDOW, MAX_CTWINDOW);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_COUNT_TYPE:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for Count/Type\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) == 0) ||
                (atoi(argv[0]) > MAX_COUNT_TYPE) ||
                (atoi(argv[0]) < MIN_COUNT_TYPE)) {
                printf("ERR:Count/Type must be in the range [%d:%d] or 255\n",
                       MIN_COUNT_TYPE, MAX_COUNT_TYPE);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_PRESENCE_REQ_TYPE:
        if (argc != 1) {
            printf
                ("ERR:Incorrect number of arguments for Presence request type\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || ((atoi(argv[0]) != 1)
                                            && (atoi(argv[0]) != 2))) {
                printf("ERR:Presence Type must be 1 or 2.\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_DURATION:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for Duration\n");
            ret = FAILURE;
        }
        break;
    case WIFIDIRECT_INTERVAL:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for Interval\n");
            ret = FAILURE;
        }
        break;
    case WIFIDIRECT_START_TIME:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for Start Time\n");
            ret = FAILURE;
        }
        break;
    case WIFIDIRECT_PRIDEVTYPEOUI:
        if (argc > MAX_PRIMARY_OUI_LEN) {
            printf
                ("ERR: Incorrect number of PrimaryDeviceTypeOUI arguments.\n");
            ret = FAILURE;
            break;
        }
        for (i = 0; i < argc; i++) {
            if (IS_HEX_OR_DIGIT(argv[i]) == FAILURE) {
                printf("ERR:Unsupported OUI\n");
                ret = FAILURE;
                break;
            }
        }
        if (!((A2HEXDECIMAL(argv[0]) == 0x00) && (A2HEXDECIMAL(argv[1]) == 0x50)
              && (A2HEXDECIMAL(argv[2]) == 0xF2) &&
              (A2HEXDECIMAL(argv[3]) == 0x04))) {
            printf("ERR:Unsupported OUI\n");
            ret = FAILURE;
            break;
        }
        break;
    case WIFIDIRECT_REGULATORYCLASS:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for RegulatoryClass\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) > MAX_REG_CLASS) ||
                (atoi(argv[0]) < MIN_REG_CLASS)) {
                printf
                    ("ERR:RegulatoryClass must be in the range [%d:%d] or 255\n",
                     MIN_REG_CLASS, MAX_REG_CLASS);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_PRIDEVTYPECATEGORY:
        if (argc != 1) {
            printf
                ("ERR:Incorrect number of arguments for PrimaryDeviceTypeCategory\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) > MAX_PRIDEV_TYPE_CAT)
                || (atoi(argv[0]) < MIN_PRIDEV_TYPE_CAT)) {
                printf
                    ("ERR:PrimaryDeviceTypeCategory must be in the range [%d:%d]\n",
                     MIN_PRIDEV_TYPE_CAT, MAX_PRIDEV_TYPE_CAT);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_SECONDARYDEVCOUNT:
        if (argc != 1) {
            printf
                ("ERR:Incorrect number of arguments for SecondaryDeviceCount\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) ||
                (atoi(argv[0]) > MAX_SECONDARY_DEVICE_COUNT)) {
                printf("ERR:SecondaryDeviceCount must be less than 15.\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_INTERFACECOUNT:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for InterfaceCount\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) ||
                (atoi(argv[0]) > MAX_INTERFACE_ADDR_COUNT)) {
                printf("ERR:IntefaceCount must be in range.[0-41]\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_GROUP_SECONDARYDEVCOUNT:
        if (argc != 1) {
            printf
                ("ERR:Incorrect number of arguments for SecondaryDeviceCount\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) ||
                (atoi(argv[0]) > MAX_GROUP_SECONDARY_DEVICE_COUNT)) {
                printf("ERR:SecondaryDeviceCount must be less than 2.\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_ATTR_CONFIG_TIMEOUT:
        if (argc != 1) {
            printf
                ("ERR:Incorrect number of arguments for Timeout Configuration\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) > 255)) {
                printf("ERR:TimeoutConfig must be in the range [0:255]\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_ATTR_EXTENDED_TIME:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for Extended time.\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) > 65535) ||
                (atoi(argv[0]) < 1)) {
                printf("ERR:Extended Time must be in the range [1:65535]\n");
                ret = FAILURE;
            }
        }
        break;

    case WIFIDIRECT_PRIDEVTYPESUBCATEGORY:
        if (argc != 1) {
            printf
                ("ERR:Incorrect number of arguments for PrimaryDeviceTypeSubCategory\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) ||
                (atoi(argv[0]) > MAX_PRIDEV_TYPE_SUBCATEGORY) ||
                (atoi(argv[0]) < MIN_PRIDEV_TYPE_SUBCATEGORY)) {
                printf
                    ("ERR:PrimaryDeviceTypeSubCategory must be in the range [%d:%d]\n",
                     MIN_PRIDEV_TYPE_SUBCATEGORY, MAX_PRIDEV_TYPE_SUBCATEGORY);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_INVITATIONFLAG:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for InvitationFlag\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) < 0) ||
                (atoi(argv[0]) > 1)) {
                printf("ERR:Invitation flag must be either 0 or 1\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_WPSCONFMETHODS:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for WPSConfigMethods\n");
            ret = FAILURE;
        } else {
            if ((IS_HEX_OR_DIGIT(argv[0]) == 0) ||
                (A2HEXDECIMAL(argv[0]) > MAX_WPS_CONF_METHODS) ||
                (A2HEXDECIMAL(argv[0]) < MIN_WPS_CONF_METHODS)) {
                printf("ERR:WPSConfigMethods must be in the range [%d:%d]\n",
                       MIN_WPS_CONF_METHODS, MAX_WPS_CONF_METHODS);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_WPSVERSION:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for WPSVersion\n");
            ret = FAILURE;
        } else {
            if ((A2HEXDECIMAL(argv[0]) < 0x10) &&
                (A2HEXDECIMAL(argv[0]) > 0x20)) {
                printf("ERR:Incorrect WPS Version %s\n", argv[0]);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_WPSSETUPSTATE:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for WPSSetupState\n");
            ret = FAILURE;
        } else {
            if ((IS_HEX_OR_DIGIT(argv[0]) == 0) ||
                ((A2HEXDECIMAL(argv[0]) != 0x01)
                 && (A2HEXDECIMAL(argv[0]) != 0x02))) {
                printf("ERR:Incorrect WPSSetupState %s\n", argv[0]);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_WPSREQRESPTYPE:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for WPSRequestType\n");
            ret = FAILURE;
        } else {
            if ((IS_HEX_OR_DIGIT(argv[0]) == 0) ||
                (A2HEXDECIMAL(argv[0]) > WPS_MAX_REQUESTTYPE)) {
                printf("ERR:Incorrect WPSRequestType %s\n", argv[0]);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_WPSSPECCONFMETHODS:
        if (argc != 1) {
            printf
                ("ERR:Incorrect number of arguments for WPSSpecConfigMethods\n");
            ret = FAILURE;
        } else {
            if ((IS_HEX_OR_DIGIT(argv[0]) == 0) ||
                ((t_u16) A2HEXDECIMAL(argv[0]) > WPS_MAX_SPECCONFMETHODS) ||
                ((t_u16) A2HEXDECIMAL(argv[0]) < WPS_MIN_SPECCONFMETHODS)) {
                printf
                    ("ERR:WPSSpecConfigMethods must be in the range [%d:%d]\n",
                     WPS_MIN_SPECCONFMETHODS, WPS_MAX_SPECCONFMETHODS);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_WPSDEVICENAME:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments\n");
            ret = FAILURE;
        } else {
            if (strlen(argv[0]) > WPS_DEVICE_NAME_MAX_LEN) {
                printf("ERR:Device name should contain"
                       " less than 32 charactors.\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_WPSMANUFACTURER:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments\n");
            ret = FAILURE;
        } else {
            if (strlen(argv[0]) > WPS_MANUFACT_MAX_LEN) {
                printf("ERR:Manufacturer name should contain"
                       "less than 64 charactors.\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_WPSMODELNAME:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments\n");
            ret = FAILURE;
        } else {
            if (strlen(argv[0]) > WPS_MODEL_MAX_LEN) {
                printf("ERR:Model name should contain"
                       " less than 64 charactors.\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_WPSUUID:
        if (argc > WPS_UUID_MAX_LEN) {
            printf("ERR: Incorrect number of WPSUUID arguments.\n");
            ret = FAILURE;
        } else {
            for (i = 0; i < argc; i++) {
                if (IS_HEX_OR_DIGIT(argv[i]) == FAILURE) {
                    printf("ERR:Unsupported UUID\n");
                    ret = FAILURE;
                    break;
                }
            }
        }
        break;
    case WIFIDIRECT_WPSPRIMARYDEVICETYPE:
        if (argc > WPS_DEVICE_TYPE_MAX_LEN) {
            printf
                ("ERR: Incorrect number of WPSPrimaryDeviceType arguments.\n");
            ret = FAILURE;
            break;
        }
        for (i = 0; i < argc; i++) {
            if (IS_HEX_OR_DIGIT(argv[i]) == FAILURE) {
                printf("ERR:Unsupported primary device type\n");
                ret = FAILURE;
                break;
            }
        }
        if (!((A2HEXDECIMAL(argv[2]) == 0x00) && (A2HEXDECIMAL(argv[3]) == 0x50)
              && (A2HEXDECIMAL(argv[4]) == 0xF2) &&
              (A2HEXDECIMAL(argv[5]) == 0x04))) {
            printf("ERR:Unsupported OUI\n");
            ret = FAILURE;
            break;
        }
        break;
    case WIFIDIRECT_WPSRFBAND:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for WPSRFBand\n");
            ret = FAILURE;
        } else {
            if ((IS_HEX_OR_DIGIT(argv[0]) == 0) ||
                ((A2HEXDECIMAL(argv[0]) != 0x01)
                 && (A2HEXDECIMAL(argv[0]) != 0x02))) {
                printf("ERR:Incorrect WPSRFBand %s\n", argv[0]);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_WPSASSOCIATIONSTATE:
        if (argc != 1) {
            printf
                ("ERR:Incorrect number of arguments for WPSAssociationState\n");
            ret = FAILURE;
        } else {
            if ((IS_HEX_OR_DIGIT(argv[0]) == 0) ||
                ((t_u16) A2HEXDECIMAL(argv[0]) > WPS_MAX_ASSOCIATIONSTATE) ||
                ((t_u16) A2HEXDECIMAL(argv[0]) < WPS_MIN_ASSOCIATIONSTATE)) {
                printf("ERR:WPSAssociationState must be in the range [%d:%d]\n",
                       WPS_MIN_ASSOCIATIONSTATE, WPS_MAX_ASSOCIATIONSTATE);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_WPSCONFIGURATIONERROR:
        if (argc != 1) {
            printf
                ("ERR:Incorrect number of arguments for WPSConfigurationError\n");
            ret = FAILURE;
        } else {
            if ((IS_HEX_OR_DIGIT(argv[0]) == 0) ||
                ((t_u16) A2HEXDECIMAL(argv[0]) > WPS_MAX_CONFIGURATIONERROR) ||
                ((t_u16) A2HEXDECIMAL(argv[0]) < WPS_MIN_CONFIGURATIONERROR)) {
                printf
                    ("ERR:WPSConfigurationError must be in the range [%d:%d]\n",
                     WPS_MIN_CONFIGURATIONERROR, WPS_MAX_CONFIGURATIONERROR);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_WPSDEVICEPASSWORD:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for WPSDevicePassword\n");
            ret = FAILURE;
        } else {
            if ((IS_HEX_OR_DIGIT(argv[0]) == 0) ||
                ((t_u16) A2HEXDECIMAL(argv[0]) > WPS_MAX_DEVICEPASSWORD) ||
                ((t_u16) A2HEXDECIMAL(argv[0]) < WPS_MIN_DEVICEPASSWORD)) {
                printf("ERR:WPSDevicePassword must be in the range [%d:%d]\n",
                       WPS_MIN_DEVICEPASSWORD, WPS_MAX_DEVICEPASSWORD);
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_WPSMODELNUMBER:
        if (argc > WPS_MODEL_MAX_LEN) {
            printf("ERR: Incorrect number of WPSModelNumber arguments.\n");
            ret = FAILURE;
        } else {
            for (i = 0; i < argc; i++) {
                if (IS_HEX_OR_DIGIT(argv[i]) == FAILURE) {
                    printf("ERR:Unsupported WPSModelNumber\n");
                    ret = FAILURE;
                    break;
                }
            }
        }
        break;
    case WIFIDIRECT_WPSSERIALNUMBER:
        if (argc > WPS_SERIAL_MAX_LEN) {
            printf("ERR: Incorrect number of WPSSerialNumber arguments.\n");
            ret = FAILURE;
        } else {
            for (i = 0; i < argc; i++) {
                if (IS_HEX_OR_DIGIT(argv[i]) == FAILURE) {
                    printf("ERR:Unsupported WPSSerialNumber\n");
                    ret = FAILURE;
                    break;
                }
            }
        }
        break;
    case WIFIDIRECT_CATEGORY:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for Category\n");
            ret = FAILURE;
        } else {
            if (ISDIGIT(argv[0]) == 0) {
                printf("ERR:Category incorrect value\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_ACTION:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for Action\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || ((atoi(argv[0]) > 0x10) &&
                                            (atoi(argv[0]) != 0xDD))) {
                printf("ERR:Action must be less than 0x10 or 0xDD\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_DIALOGTOKEN:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for DialogToken\n");
            ret = FAILURE;
        } else {
            if (ISDIGIT(argv[0]) == 0) {
                printf("ERR:DialogToken incorrect value\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_GAS_COMEBACK_DELAY:
        if (argc != 1) {
            printf
                ("ERR:Incorrect number of arguments for GAS Comeback Delay\n");
            ret = FAILURE;
        }
        break;
    case WIFIDIRECT_DISC_ADPROTOIE:
        if (argc > MAX_ADPROTOIE_LEN) {
            printf
                ("ERR: Incorrect number of AdvertisementProtocolIE arguments.\n");
            ret = FAILURE;
            break;
        }
        for (i = 0; i < argc; i++) {
            if (IS_HEX_OR_DIGIT(argv[i]) == FAILURE) {
                printf("ERR:Unsupported AdvertisementProtocolIE\n");
                ret = FAILURE;
                break;
            }
        }
        break;
    case WIFIDIRECT_DISC_INFOID:
        if (argc > MAX_INFOID_LEN) {
            printf
                ("ERR: Incorrect number of DiscoveryInformationID arguments.\n");
            ret = FAILURE;
            break;
        }
        if (!
            ((A2HEXDECIMAL(argv[0]) == 0xDD) && (A2HEXDECIMAL(argv[1]) == 0xDD))
            && !((A2HEXDECIMAL(argv[0]) == 0xDE) &&
                 (A2HEXDECIMAL(argv[1]) == 0x92))) {
            printf("ERR:Unsupported DiscoveryInformationID\n");
            ret = FAILURE;
        }
        break;
    case WIFIDIRECT_OUI:
        if (argc > MAX_OUI_LEN) {
            printf("ERR: Incorrect number of OUI arguments.\n");
            ret = FAILURE;
            break;
        }
        for (i = 0; i < argc; i++) {
            if (IS_HEX_OR_DIGIT(argv[i]) == FAILURE) {
                printf("ERR:Unsupported OUI\n");
                ret = FAILURE;
                break;
            }
        }
        break;
    case WIFIDIRECT_OUITYPE:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for OUIType\n");
            ret = FAILURE;
        } else {
            if (ISDIGIT(argv[0]) == 0) {
                printf("ERR:OUIType incorrect value\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_OUISUBTYPE:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for OUISubtype\n");
            ret = FAILURE;
        } else {
            if (ISDIGIT(argv[0]) == 0) {
                printf("ERR:OUISubtype incorrect value\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_DISC_SERVICEPROTO:
        if (argc != 1) {
            printf
                ("ERR:Incorrect number of arguments for DiscoveryServiceProtocol\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || ((atoi(argv[0]) >= 4) &&
                                            (atoi(argv[0]) != 0xFF))) {
                printf("ERR:DiscoveryServiceProtocol incorrect value\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_SERVICEUPDATE_INDICATOR:
        if (argc != 1) {
            printf
                ("ERR:Incorrect number of arguments for ServiceUpdateIndicator\n");
            ret = FAILURE;
        } else {
            if (ISDIGIT(argv[0]) == 0) {
                printf("ERR:ServiceUpdateIndicator incorrect value\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_DISC_SERVICETRANSACID:
        if (argc != 1) {
            printf
                ("ERR:Incorrect number of arguments for DiscoveryServiceTransactionID\n");
            ret = FAILURE;
        } else {
            if (ISDIGIT(argv[0]) == 0) {
                printf("ERR:DiscoveryServiceTransactionID incorrect value\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_DISC_SERVICE_STATUS:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for ServiceStatus\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || (atoi(argv[0]) >= 4)) {
                printf("ERR:ServiceStatus incorrect value\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_DISC_DNSTYPE:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for DiscoveryDNSType\n");
            ret = FAILURE;
        } else {
            if (ISDIGIT(argv[0]) == 0) {
                printf("ERR:DiscoveryDNSType incorrect value\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_DISC_BONJOUR_VERSION:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for Version\n");
            ret = FAILURE;
        } else {
            if (ISDIGIT(argv[0]) == 0) {
                printf("ERR:Version incorrect value\n");
                ret = FAILURE;
            }
        }
        break;
    case WIFIDIRECT_DISC_UPNP_VERSION:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for Version\n");
            ret = FAILURE;
        }
        break;
    case WIFIDIRECT_ENABLE_SCAN:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for EnableScan\n");
            ret = FAILURE;
        } else {
            if ((ISDIGIT(argv[0]) == 0) || ((atoi(argv[0]) != 0) &&
                                            (atoi(argv[0]) != 1))) {
                printf("ERR:EnableScan must be 0 or 1.\n");
                ret = FAILURE;
            }
        }
        break;

    case WIFIDIRECT_DEVICE_STATE:
        if (argc != 1) {
            printf("ERR:Incorrect number of arguments for DeviceState\n");
            ret = FAILURE;
        } else {
            if (ISDIGIT(argv[0]) == 0) {
                printf("ERR:Incorrect DeviceState.\n");
                ret = FAILURE;
            }
        }
        break;

    default:
        printf("Parameter validity for %d ignored\n", cmd);
        break;
    }
    return ret;
}

/** Structure of command table*/
typedef struct
{
        /** Command name */
    char *cmd;
        /** Command function pointer */
    void (*func) (int argc, char *argv[]);
        /** Command usuage */
    char *help;
} command_table;

/** WiFiDisplay command table */
static command_table wifidisplay_command[] = {
    {"wifidisplay_config", wifidisplaycmd_config,
     "\tSet/get wifidisplay configuration"},
    {"wifidisplay_mode", wifidisplay_cmd_status,
     "\tSet/get WFD Display status"},
    {"wifidisplay_update_devinfo", wifidisplay_update_custom_ie,
     "\tUpdate WFD device info bitmap"},
    {"wifidisplay_update_coupledsink_bitmap",
     wifidisplay_update_coupledsink_bitmap, "\tUpdate WFD coupled sink bitmap"},
    {"wifidisplay_discovery_request", wifidisplaycmd_service_discovery,
     "Send wifidisplay service discovery request"},
    {"wifidisplay_discovery_response", wifidisplaycmd_service_discovery,
     "Send wifidisplay service discovery response"},
    {NULL, NULL, 0},
};

/** WIFIDIRECT command table */
static command_table wifidirect_command[] = {
    {"wifidirect_config", wifidirectcmd_config,
     "\tSet/get wifidirect configuration"},
    {"wifidirect_params_config", wifidirectcmd_params_config,
     "\tSet/get wifidirect parameter's configuration"},
    {"wifidirect_action_frame", wifidirectcmd_action_frame,
     "\tSend wifidirect action frame."},
    {"wifidirect_mode", wifidirectcmd_status,
     "\tSet/get WIFIDIRECT start/stop status"},
    {"wifidirect_discovery_request", wifidirectcmd_service_discovery,
     "Send wifidirect service discovery request"},
    {"wifidirect_discovery_response", wifidirectcmd_service_discovery,
     "Send wifidirect service discovery response"},
    {"wifidirect_gas_comeback_request", wifidirectcmd_gas_comeback_discovery,
     "Send wifidirect GAS comeback request frame"},
    {"wifidirect_gas_comeback_response", wifidirectcmd_gas_comeback_discovery,
     "Send wifidirect GAS comeback response frame"},
    {"wifidirect_cfg_persistent_group_record",
     wifidirect_cfg_cmd_persistent_group_record,
     "Set/get information about a persistent group"},
    {"wifidirect_cfg_persistent_group_invoke",
     wifidirect_cfg_cmd_persistent_group_invoke,
     "Invoke or disable a persistent group"},
    {"wifidirect_cfg_discovery_period", wifidirect_cfg_cmd_discovery_period,
     "\tSet/get discovery period"},
    {"wifidirect_cfg_intent", wifidirect_cfg_cmd_intent, "\tSet/get intent"},
    {"wifidirect_cfg_capability", wifidirect_cfg_cmd_capability,
     "\tSet/get capability"},
    {"wifidirect_cfg_noa", wifidirect_cfg_cmd_noa,
     "\tSet/get notice of absence"},
    {"wifidirect_cfg_opp_ps", wifidirect_cfg_cmd_opp_ps,
     "\tSet/get Opportunistic PS"},
    {"wifidirect_cfg_invitation_list", wifidirect_cfg_cmd_invitation_list,
     "\tSet/get invitation list"},
    {"wifidirect_cfg_listen_channel", wifidirect_cfg_cmd_listen_channel,
     "\tSet/get listen channel"},
    {"wifidirect_cfg_op_channel", wifidirect_cfg_cmd_op_channel,
     "\tSet/get operating channel"},
    {"wifidirect_cfg_presence_req_params",
     wifidirect_cfg_cmd_presence_req_params,
     "\tSet/get presence request parameters"},
    {"wifidirect_cfg_ext_listen_time", wifidirect_cfg_cmd_ext_listen_time,
     "Set/get extended listen timing parameters"},
    {"wifidirect_cfg_provisioning_params",
     wifidirect_cfg_cmd_provisioning_params,
     "Set/get provisioning protocol related parameters"},
    {"wifidirect_cfg_wps_params", wifidirect_cfg_cmd_wps_params,
     "Set/get WPS protocol related parameters"},
    {NULL, NULL, 0}
};

/** 
 *  @brief Entry function for wifidirectutl
 *  @param argc         number of arguments
 *  @param argv     A pointer to arguments array    
 *  @return             SUCCESS or FAILURE
 */
int
main(int argc, char *argv[])
{
    int i;

    if (argc < 3) {
        print_tool_usage();
        exit(1);
    }

    strncpy(dev_name, argv[1], IFNAMSIZ);
    /* Process command */
    for (i = 0; wifidirect_command[i].cmd; i++) {
        if (strncmp
            (wifidirect_command[i].cmd, argv[2],
             strlen(wifidirect_command[i].cmd)))
            continue;
        if (strlen(wifidirect_command[i].cmd) != strlen(argv[2]))
            continue;
        wifidirect_command[i].func(argc, argv);
        break;
    }
    for (i = 0; wifidisplay_command[i].cmd; i++) {
        if (strncmp
            (wifidisplay_command[i].cmd, argv[2],
             strlen(wifidisplay_command[i].cmd)))
            continue;
        if (strlen(wifidisplay_command[i].cmd) != strlen(argv[2]))
            continue;
        wifidisplay_command[i].func(argc, argv);
        break;
    }
    if ((!wifidirect_command[i].cmd) && (!wifidisplay_command[i].cmd)) {
        printf("ERR: %s is not supported\n", argv[2]);
        exit(1);
    }
    return 0;

}
